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

entity charGen_toplevel is
	port(
		clk: in std_logic;
		rgb: out std_logic_vector(7 downto 0);
		hs_out, vs_out: out std_logic;
		sw: in std_logic_vector(7 downto 0);
		seg : out std_logic_vector(6 downto 0);
		an : out std_logic_vector(3 downto 0) := "1100";		
		dp : out std_logic;
		btn: in std_logic_vector(3 downto 0);
		ps2_clk    : IN  STD_LOGIC;                     --clock signal from PS2 keyboard
      ps2_data   : IN  STD_LOGIC;
		btwn: out std_logic
	);
end charGen_toplevel;

architecture top_charGen of charGen_toplevel is

	component ps2_keyboard_to_ascii is
	generic(
      clk_freq                  : INTEGER := 50_000_000; --system clock frequency in Hz
      ps2_debounce_counter_size : INTEGER := 8           --set such that 2^size/clk_freq = 5us (size = 8 for 50MHz)
		);         
   port(
      clk        : IN  STD_LOGIC;                     --system clock input
      ps2_clk    : IN  STD_LOGIC;                     --clock signal from PS2 keyboard
      ps2_data   : IN  STD_LOGIC;                     --data signal from PS2 keyboard                 
      ascii_code : OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
		ascii_new  : OUT STD_LOGIC
		); 
	end component;
	
	component charGen is
	port(
		clk: in std_logic;
		char_we: in std_logic;
		char_value: in std_logic_vector(7 downto 0);
		char_addr: in std_logic_vector(11 downto 0);
		pixel_x: in std_logic_vector(9 downto 0);
		pixel_y: in std_logic_vector(9 downto 0);
		pixel_out: out std_logic
	);
	end component;
	
	component vga_timing is
	port(
		clk, rst: in std_logic;
		HS: out std_logic;
		VS: out std_logic;
		pixel_x, pixel_y: out std_logic_vector(9 downto 0);
		last_column, last_row: out std_logic;
		blank: out std_logic
	);
	end component;
	
	component seven_segment_display is
		generic(
			COUNT: natural := 15
		);	
		port(
			clk: in std_logic;
			data_in: in std_logic_vector(15 downto 0);
			dp_in: in std_logic_Vector(3 downto 0);
			blank: in std_logic_vector(3 downto 0);
			seg : out std_logic_vector(6 downto 0);
			dp : out std_logic;
			an : out std_logic_vector(3 downto 0)
		);
	end component;
	
	component tx is
		generic(
			CLK_RATE: natural := 50_000_000;
			BAUD_RATE: natural := 19_200
		);
		port(
			clk: in std_logic;
			rst: in std_logic;
			data_in: in std_logic_vector(7 downto 0);
			send_character: in std_logic;
			tx_out: out std_logic;
			tx_busy:out std_logic
			
		);
	end component;
	
	signal temp_x,temp_y: std_logic_vector(9 downto 0);
	signal hs,vs: std_logic;
	signal temp_hs,temp_vs: std_logic := '0';
	signal reset: std_logic := '0';
	signal dp_in: std_logic_vector(3 downto 0) := "0000";
	signal blank4: std_logic_vector(3 downto 0) := (others=>'0');	
	signal data_in: std_logic_vector(15 downto 0) := (others=>'0');
	signal data_in123: std_logic_vector(7 downto 0) := (others=>'0');
	signal pixel_out: std_logic;
	signal count: natural := 0;
	signal count_next: natural;
	signal count_en: std_logic;
	signal count_key: natural := 0;
	signal count_next_key: natural;
	signal count_en_key: std_logic;
	signal count_en_start: std_logic;
	signal char_we: std_logic;
	signal row_position, column_position: natural := 0;
	signal row_next, column_next: natural;
	signal row_en: std_logic;
	signal char_write_addr: std_logic_vector(11 downto 0) := (others=>'0');
	signal blank: std_logic := '0';
	signal font_color: std_logic_vector(7 downto 0) := (others=>'1');
	signal back_color: std_logic_vector(7 downto 0) := (others => '0');
	signal ascii_new_temp  : STD_LOGIC;                     --output flag indicating new ASCII value
   signal ascii_code_temp : STD_LOGIC_VECTOR(6 DOWNTO 0); --ASCII value
	signal ascii_code_buf	: Std_logic_vector(7 downto 0);

	signal go : std_logic:='0';
	signal tx_out : std_logic;
	signal tx_busy: std_logic;
	begin
		
		bottom_tx: tx
		port map(clk=>clk, rst=>reset, send_character=>ascii_new_temp, 
					tx_out=>tx_out, tx_busy=>tx_busy, data_in=>data_in123
				);
	
		bottom_ps2: ps2_keyboard_to_ascii
		port map(clk=>clk,ps2_clk=>ps2_clk,ps2_data=>ps2_data,ascii_new=>ascii_new_temp,ascii_code=>ascii_code_temp
		);
		
		bottom_level: vga_timing
		port map(clk=>clk, rst=>reset, pixel_x=>temp_x, pixel_y=>temp_y, blank=>blank,
					HS=>hs, VS=>vs, last_column=>open, last_row=>open
				);
		
		bottom_charGen: charGen
		port map(clk=>clk, char_we=>char_we, char_value=>ascii_code_buf, char_addr=>char_write_addr, pixel_x=>temp_x, pixel_y=>temp_y, pixel_out=>pixel_out
				);
		
		bottom_segment: seven_segment_display
		generic map(COUNT=>15)
		port map(clk=>clk, an=>an, seg=>seg, dp=>dp, blank=>blank4,
					data_in=>data_in, dp_in=>dp_in
				);
		ascii_code_buf <= "0" & ascii_code_temp;
		data_in <= "000000000" & ascii_code_temp;
		data_in123 <= std_logic_vector(unsigned("0" & ascii_code_temp) + unsigned(sw));
		
		
			
		-- DELAY for char_gen
		process(clk)
		begin
			if(rising_edge(clk)) then
				count <= count_next;
			end if;
		end process;
		count_next <= 0 when count=3000000 else
						  count + 1;
		count_en <= '1' when count=3000000 else
						'0';

		-- ROW AND COL LOGIC
		
		row_next <= row_position+1 when row_position < 30 else
						0;
		column_next <= column_position+1 when column_position < 79 else
						0;
		row_en <= '1' when column_position = 79 else
					 '0';
		char_write_addr <= std_logic_vector(to_unsigned(row_position,5)) & std_logic_vector(to_unsigned(column_position,7));

		font_color <= sw;
		back_color <= not sw;
		-- COLOR
		rgb <= std_logic_vector(font_color) when pixel_out='1' else
				 std_logic_vector(back_color) when blank = '0' else
				 "00000000";
		btwn <= tx_out;
		process(clk)
		begin
			if(rising_edge(clk)) then
				if(ascii_new_temp = '1') then
					go <='1';
				end if;
				if(char_we = '1') then
					go <='0';
				end if;
			end if;
		end process;
		
		-- BUTTON
		char_we <= '1' when count_en = '1' and go = '1' else '0';
		process(clk,ascii_new_temp,count_en)
		begin
			if(rising_edge(clk)) then
				if (btn(3)='1') then
					reset <= '1';
					column_position <= 0;
					row_position <= 0;
				elsif (go = '1') then
					if(count_en='1') then
						reset <= '0';
						column_position <= column_next;
						if(row_en='1') then
							row_position <= row_next;
						end if;
					end if;				
				else
					reset <= '0';
				end if;
			end if;
		end process;
		
		-- DELAYS
		process(clk,hs,vs)
		begin
			if(rising_edge(clk)) then
				temp_hs <= hs;
				temp_vs <= vs;
				hs_out <= temp_hs;
				vs_out <= temp_vs;						
			end if;
		end process;
		
end top_charGen;