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

use std.textio.all;

entity sim is
	generic (
		OUTPUT_WIDTH : positive;
		STEP : natural range 1 to 2
	);
end entity;

architecture aoc_stdio of sim is
	type char_file_t is file of character;
	file stdin : char_file_t open READ_MODE is "STD_INPUT";

	signal char_in : character;
	signal clk, reset, input_valid, output_valid : std_logic;
	signal output : unsigned(OUTPUT_WIDTH-1 downto 0);

	procedure print(s: string) is
		variable l : line;
	begin
		write(l, s);
		writeline(std.textio.output, l);
	end procedure;

	component dut is
		generic (
			OUTPUT_WIDTH : positive;
			STEP : natural range 1 to 2
		);
		port (
			clk : in std_logic;
			reset : in std_logic;

			char  : in character;
			input_valid : in std_logic;

			output : out unsigned(OUTPUT_WIDTH-1 downto 0);
			output_valid : out std_logic
		);
	end component;
begin
	process
		variable current_char : character;
		variable good : boolean;

		procedure cycle_clock is
		begin
			wait for 10 ns;
			clk <= '0';
			wait for 10 ns;
			clk <= '1';
			wait for 0 ns;
		end procedure;
	begin
		clk <= '0';
		input_valid <= '0';
		char_in <= NUL;

		reset <= '1';
		cycle_clock;
		reset <= '0';
		cycle_clock;

		input_valid <= '1';

		chars_loop: while not endfile(stdin) loop
			read(stdin, current_char);

			char_in <= current_char;
			cycle_clock;
		end loop;

		input_valid <= '0';
		cycle_clock;
		cycle_clock;

		assert output_valid report "Output was not valid at end of simulation" severity failure;
		print(to_string(to_integer(output)));

		wait;
	end process;

	dut_inst: dut
		generic map (
			OUTPUT_WIDTH => OUTPUT_WIDTH,
			STEP => STEP
		)
		port map (
			clk => clk,
			reset => reset,
			char => char_in,
			input_valid => input_valid,
			output => output,
			output_valid => output_valid
		);
end architecture;
