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

entity nes_controller_tb is
end entity;

architecture bench of nes_controller_tb is

	signal clk   : std_logic := '-';
	signal res_n : std_logic := '-';

	signal nes_data     : std_logic := '-';
	signal nes_clk      : std_logic := '-';
	signal nes_latch    : std_logic := '-';
	signal button_state : nes_buttons_t;

	signal stop_clock : boolean := false;

	constant CLK_PERIOD      : time := 20 ns;
	constant CLK_OUT_PERIOD  : time := 1 us;
	constant CLK_FREQ        : integer := 50e6;
	constant CLK_OUT_FREQ    : integer := 1e6;
	constant REFRESH_TIMEOUT : integer := 1e2;
	-- 11907086 mod 2^16 = (45070)_10 = (1011 0000 0000 1110)_2
	-- maps to (a, b, select, start, up, down, left, right)
	constant b_0 : std_logic_vector(7 downto 0) := "10110000";
	constant b_1 : std_logic_vector(7 downto 0) := "00001110";

begin

	nes_controller_inst : nes_controller
	generic map (
		CLK_FREQ => CLK_FREQ,
		CLK_OUT_FREQ => CLK_OUT_FREQ,
		REFRESH_TIMEOUT => REFRESH_TIMEOUT
	)
	port map (
		clk => clk,
		res_n => res_n,

		nes_data => nes_data,
		nes_clk => nes_clk,
		nes_latch => nes_latch,
		button_state => button_state
	);

	generate_nes : process
	begin
		res_n <= '0';
		wait for 250 ns;
		wait until rising_edge(clk);
		res_n <= '1';

		-- feed b_0
		wait until nes_latch = '1';
		for i in 7 downto 0 loop
			nes_data <= b_0(i);
			wait until rising_edge(nes_clk);
		end loop;

		-- feed b_1
		wait until nes_latch = '1';
		for i in 7 downto 0 loop
			nes_data <= b_1(i);
			wait until rising_edge(nes_clk);
		end loop;

		-- a last wait to get the next `button_state`
		wait until nes_latch = '1';
		stop_clock <= true;
	end process;

	-- taken from top_tb
	generate_clk : process
	begin
		while not stop_clock loop
			clk <= '0', '1' after CLK_PERIOD / 2;
			wait for CLK_PERIOD;
		end loop;
		wait;
	end process;

end architecture;
