--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:    11:25:45 10/15/05
-- Design Name:    
-- Module Name:    vga_ctrl_top - Behavioral
-- Project Name:   
-- Target Device:  
-- Tool versions:  
-- Description:
--
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

use work.vga_types.all;
use work.cpu_pkg.all;

entity vga_ctrl_top is
	Generic
	(
		sys_freq		: real		:= 100.0;
		fifo_depth		: integer	:= 2048;
		tsvga			: vga_timespec_t := ts_vga_1280_1024_72
	);
	Port
	(
		sys_rstn_in		: in std_logic;
		sys_clk_in		: in std_logic;
		sys_vga_red		: out unsigned(7 downto 0);
		sys_vga_green	: out unsigned(7 downto 0);
		sys_vga_blue	: out unsigned(7 downto 0);
		sys_vga_blank_n	: out std_logic;
		sys_vga_sync_n	: out std_logic;
		sys_vga_hsync	: out std_logic;
		sys_vga_vsync	: out std_logic;
		sys_vga_clk		: out std_logic;
		-- Buttons and LEDs
		sys_btn			: in unsigned(4 downto 0);
		sys_dip			: in unsigned(7 downto 0);
		sys_led			: out unsigned(8 downto 0)
	);
end vga_ctrl_top;

architecture Behavioral of vga_ctrl_top is

	-- System signal
	signal rst                    : std_logic;
	signal clk                    : std_logic;
	signal vga_rst                : std_logic;
	signal vga_clk                : std_logic;
	signal vga_ready              : std_logic;

	--	Timing
	signal scan_rdy               : std_logic;
	signal scan_rdy_h             : std_logic;
	signal scan_rdy_v             : std_logic;
	signal vga_scan_x             : std_logic;
	signal vga_scan_y             : std_logic;
	signal hsync                  : std_logic;
	signal vsync                  : std_logic;

	signal src_pos_x		       	: natural range 0 to tsvga.ts_h.ncyc_scan-1;
	signal src_pos_y		      	: natural range 0 to tsvga.ts_v.ncyc_scan-1;
	signal vga_pos_x		       	: natural range 0 to tsvga.ts_h.ncyc_scan-1;
	signal vga_pos_y		      	: natural range 0 to tsvga.ts_v.ncyc_scan-1;

	-- Line buffers
	signal color_w					: color_t;
	signal vga_color				: color_t;
	signal color_we					: std_logic;
	signal fifo_full				: std_logic;
	signal fifo_almost_full			: std_logic;
	signal scan_enable				: std_logic;
	signal src_enable				: std_logic;
	signal src_cnt_en				: std_logic;
	signal char_draw_en				: std_logic;
	signal cg_en					: std_logic;
	signal cpu_color				: color_t;

	-- CPU signals
	signal cpu_rst					: std_logic;
	signal cpu_ce					: std_logic;
	signal cpu_int_in				: std_logic;
	signal cpu_int_ack				: std_logic;
	signal cpu_we					: std_logic;
	signal cpu_re					: std_logic;
	signal cpu_io_sel				: std_logic;
	signal cpu_din 					: dmem_data_t;
	signal cpu_dout					: dmem_data_t;
	signal cpu_addr					: dmem_addr_t;
	signal cpu_xrom_data			: dmem_data_t;

	signal cg_ready					: std_logic;
	signal cg_clr_screen			: std_logic;
	signal cg_clr_line				: std_logic;
	signal cg_ascii_data			: dmem_data_t;
	signal cg_ascii_data_we			: std_logic;
	signal cg_ascii_posy_we			: std_logic;
	signal cg_ascii_posx_we			: std_logic;
	
	signal cpu_led					: dmem_data_t;
	signal cpu_red					: dmem_data_t;
	signal cpu_green				: dmem_data_t;
	signal cpu_blue					: dmem_data_t;

begin

	inst_vga_backend: entity work.vga_backend
	GENERIC MAP
	(
		sys_freq	=> sys_freq,
		fifo_depth	=> fifo_depth,
		tsvga		=> tsvga
	)		
	PORT MAP
	(
		sys_rst				=> vga_rst,
		sys_clk				=> clk,
		vga_ready			=> vga_ready,
		color_in			=> color_w,
		color_fifo_we		=> color_we,
		color_fifo_full		=> fifo_full,
		color_fifo_afull	=> fifo_almost_full,
		direct_color_in		=> cpu_color,
		direct_draw_en		=> char_draw_en,
		stat_hsync			=> hsync,	
		stat_vsync			=> vsync,
		stat_hready			=> scan_rdy_h,
		stat_vready			=> scan_rdy_v,
		stat_hscan			=> vga_scan_x,
		stat_vscan			=> vga_scan_y,
		stat_hpos			=> vga_pos_x,
		stat_vpos			=> vga_pos_y,
		vga_clk_out			=> vga_clk,
		vga_color_out		=> vga_color,
		vga_blank_n			=> sys_vga_blank_n,
		vga_sync_n			=> sys_vga_sync_n,
		vga_hsync			=> sys_vga_hsync,
		vga_vsync			=> sys_vga_vsync
		
	);

	inst_char_gen : entity work.char_gen
	GENERIC MAP
	(
		tsvga				=> tsvga,
		CHARACTER_SCALE		=> 1,
		CHAR_ROM_SIZE_X		=> 8,	-- Pixels
		CHAR_ROM_SIZE_Y		=> 16,	-- Pixels
		CHAR_ROM_DEPTH		=> 256,	-- Chars
		MAX_CHAR_PER_LINE	=> 80,	-- Chars
		MAX_LINE_PER_FRAME	=> 32,	-- Chars
		CHAR_SPACING_X		=> 0, 	-- Pixels
		CHAR_SPACING_Y		=> 0,	-- Pixels
		SCREEN_OFFSET_X		=> 16,	-- Pixels
		SCREEN_OFFSET_Y		=> 16	-- Pixels
	)		
	PORT MAP
	(
	    rst				=> rst,
	    sys_clk			=> clk,
	    vga_clk			=> vga_clk,
	    ce				=> cg_en,
	    frame_pulse		=> scan_rdy,
	    clr_screen		=> cg_clr_screen,
	    clr_line		=> cg_clr_line,
	    ascii_data		=> cg_ascii_data,
	    ascii_data_we	=> cg_ascii_data_we,
	    ascii_posy_we	=> cg_ascii_posy_we,
	    ascii_posx_we	=> cg_ascii_posx_we,
	    ready			=> cg_ready,
	    pos_x			=> vga_pos_x,
	    pos_y			=> vga_pos_y,
	    char_draw_en	=> char_draw_en
    );

	inst_cpu_embedded: entity work.cpu_embedded
	PORT MAP(
		rst => cpu_rst,
		clk => clk,
		ce => cpu_ce,
		int_in => cpu_int_in,
		int_ack => cpu_int_ack,
		xmem_we => cpu_we,
		xmem_re => cpu_re,
		xmem_din => cpu_din,
		xmem_dout => cpu_dout,
		xmem_addr => cpu_addr,
		io_sel => cpu_io_sel
	);

	inst_xrom: entity work.xrom
	PORT MAP(
		clk			=> clk,
		ce			=> cpu_ce,
		addr		=> cpu_addr,
		dout 		=> cpu_xrom_data
	);

	---------------------------------------------------------------------------------------------
	rst             <= not vga_ready;
	vga_rst			<= not sys_rstn_in;
	
--	clk				<= vga_clk;
	clk				<= sys_clk_in;

	scan_rdy		<= scan_rdy_h and scan_rdy_v;

	sys_vga_clk		<= vga_clk;
	sys_vga_red		<= vga_color(r);
	sys_vga_green	<= vga_color(g);
	sys_vga_blue	<= vga_color(b);

	cg_en 			<= vga_scan_x and vga_scan_y;
	cpu_ce			<= '1';
	
	---------------------------------------------------------------------------------------------
led_out: process (clk)
	begin
		if rising_edge(clk) then
			sys_led	<= '0' & cpu_led;
		end if;
	end process;

	---------------------------------------------------------------------------------------------
cpu_reg_read:
	process(clk, cpu_io_sel, cpu_xrom_data)
	variable reg : dmem_data_t;
	begin
		
		if rising_edge(clk) then
			case cpu_addr is
			when X"00" =>	-- 00
				reg := "000" & unsigned(sys_btn(4 downto 0));
			when X"01" =>	-- 01 
				reg := cpu_led;
			when X"05" =>	-- 05 
				reg := unsigned(sys_dip);
			when X"0B" =>
				reg := "000000" & cg_ready & vga_ready;
			when others => null;
			end case;
		end if;	
		
		cpu_din <= cpu_xrom_data;
		if cpu_io_sel = '1' then
			cpu_din <= reg;
		end if;	

	end process;
	
------------------------------------------------------------------
cpu_reg_write:
	process(rst, clk)
	variable addr : unsigned(dmem_addr_t'length-1 downto 0);
	begin
		if (rst = '1') then
			cpu_led <= (others => '0');
			cg_ascii_data		<= (others => '0');
			cg_ascii_posy_we	<= '0';
			cg_ascii_posx_we	<= '0';
			cg_ascii_data_we	<= '0';
			cg_clr_line			<= '0';
			cg_clr_screen		<= '0';
			cpu_red				<= X"80";
			cpu_green			<= X"80";
			cpu_blue			<= X"80";
			
		elsif rising_edge(clk) then
			cg_ascii_posy_we	<= '0';
			cg_ascii_posx_we	<= '0';
			cg_ascii_data_we	<= '0';
			cg_clr_line			<= '0';
			cg_clr_screen		<= '0';
			addr := cpu_addr;
			if cpu_we = '1' then	
				if cpu_io_sel = '1' then
					case addr is
						when X"01" =>	-- 01
							cpu_led <= cpu_dout;
						when X"02" =>	-- 04
							cpu_red <= cpu_dout;
						when X"03" =>	-- 04
							cpu_green <= cpu_dout;
						when X"04" =>	-- 04
							cpu_blue <= cpu_dout;
						when X"08" =>	-- 08
							cg_ascii_data 		<= cpu_dout;
						    cg_ascii_posx_we	<= '1';
						when X"09" =>	-- 09
							cg_ascii_data 		<= cpu_dout;
						    cg_ascii_posy_we	<= '1';
						when X"0A" =>	-- 0A
							cg_ascii_data 		<= cpu_dout;
							cg_ascii_data_we	<= '1';
						when X"0B" =>	-- 0B
							cg_clr_screen	<= cpu_dout(0);
							cg_clr_line		<= cpu_dout(1);
						when others => null;
					end case;
				end if;	
			end if;	
		end if;	
	end process;

	---------------------------------------------------------------------------------------------
	--- Test
	---------------------------------------------------------------------------------------------
	cpu_start: process (rst, vga_clk)
	begin
		if (rst = '1') then
			cpu_rst <= '1';
		elsif rising_edge(vga_clk) and scan_rdy = '1' then
			cpu_rst <= '0';
		end if;	
	end process;

	scan_start: process (rst, clk)
	begin
		if (rst = '1') then
			scan_enable <= '0';
		elsif rising_edge(clk) then
			scan_enable <= '1';
		end if;	
	end process;

	color_sel: process (vga_clk)
	begin
		if rising_edge(vga_clk) and scan_rdy = '1' then
			cpu_color	<= (cpu_red, cpu_green, cpu_blue);
		end if;
	end process;

	color_we <= scan_enable and src_enable and not fifo_full;
	
	src_inc_reg: process (rst, clk)
	begin
		if (rst = '1') then
			src_enable	<= '0';
		elsif rising_edge(clk) then
			if fifo_full = '1' then
				src_enable <= '0';
			elsif fifo_almost_full = '0' then
				src_enable <= '1';
			end if;	
		end if;
	end process;

	color_ctrl: process (rst, clk)
	variable enable : std_logic;
	begin
		if (rst = '1') then
			src_pos_x	<= 0;
			src_pos_y	<= 0;
		elsif rising_edge(clk) then
			if color_we = '1' then
				if src_pos_x < tsvga.ts_h.ncyc_scan-1 then
					src_pos_x	<= src_pos_x + 1;
				else	
					src_pos_x	<= 0;
					if src_pos_y < tsvga.ts_v.ncyc_scan-1 then
						src_pos_y	<= src_pos_y + 1;
					else	
						src_pos_y	<= 0;
					end if;	
				end if;	
			end if;
		end if;
	end process;

	color_gen: process (src_pos_x, src_pos_y)
	begin
		color_w		<= (X"00", X"00", X"00");
		if src_pos_y = 0 then
			color_w <= (X"00", X"FF", X"00");
		elsif src_pos_y = (tsvga.ts_v.ncyc_scan-1) then
			color_w <= (X"00", X"FF", X"00");
		elsif src_pos_x = 0 then
			color_w <= (X"FF", X"00", X"00");
		elsif src_pos_x = (tsvga.ts_h.ncyc_scan-1) then
			color_w <= (X"00", X"00", X"FF");
		end if;	
	end process;
	
end Behavioral;
