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

library std;
use std.textio.all;

entity tb is
end entity;

architecture bench of tb is
	constant CLK_PERIOD : time := 10 ns;
    
	signal stop : boolean := false;
    
	signal clk : std_logic;
	signal clk_en : std_logic;
	signal reset : std_logic := '0';
    
	signal dataa : std_logic_vector(31 downto 0);
	signal datab : std_logic_vector(31 downto 0);
	signal result : std_logic_vector(31 downto 0);

	type test_vector_t is array (0 to 4) of std_logic_vector(31 downto 0);
	type result_vector_t is array (0 to 14) of std_logic_vector(31 downto 0);

	constant test_vector : test_vector_t := (
		x"00010000", -- one
		x"11110000", -- -one
		x"fff842ab", -- x
		x"ffe2859a", -- y
		x"001e3999"  -- z
	);
	constant result_vector : result_vector_t := (
		x"00010000", -- one * one
		x"11110000", -- one * -one
		x"fff842ab", -- one * x
		x"ffe2859a", -- one * y
		x"001e3999", -- one * z
		x"00010000", -- -one * -one
		x"00010000", -- -one * x
		x"00010000", -- -one * y
		x"00010000", -- -one * z
		x"003be6ac", -- x * x
		x"00e425f0", -- x * y
		x"ff161241", -- x * z
		x"0364f5a1", -- y * y
		x"fc85062d", -- y * z
		x"03918cd1"  -- z * z
	);

    begin
	ci_mul_inst : entity work.ci_mul
	port map (
	    clk       => clk,
	    clk_en    => clk_en,
	    reset     => reset,
	    dataa     => dataa,
	    datab     => datab,
	    result    => result
	);
    
	stimulus : process
		variable ri : integer := -2;
	begin
		reset <= '1';
		dataa <= x"00000000";
		datab <= x"00000000";
		wait for 50 ns;
		for i in 0 to test_vector'length - 1 loop
			for j in i to test_vector'length - 1 loop
				wait until rising_edge(clk);
				if not (i = 0 and j = 0) then
					report "testing dataa=" & to_string(dataa) & " * datab=" & to_string(datab);
				end if;
				if ri > -1 then
					report "correct=" & to_string(result = result_vector(ri));
					report "  result=" & to_string(result);
					report "  actual=" & to_string(result_vector(ri));
				end if;
				wait until rising_edge(clk);
				if i = 0 and j = 0 then
					reset <= '0';
					clk_en <= '1';
				end if;
				dataa <= test_vector(i);
				datab <= test_vector(j);
				ri := ri + 1;
			end loop;
		end loop;
		wait until rising_edge(clk);
		clk_en <= '0';
		stop <= true;
		wait;
	end process;
    
	generate_clk : process
	begin
		while not stop loop
			clk <= '1', '0' after CLK_PERIOD / 2;
			wait for CLK_PERIOD;
		end loop;
		wait;
	end process;
    
    end architecture;
    
