formal: block
	signal prev_a : MATH_WORD;
	signal prev_b : MATH_WORD;
	signal prev_operation : alu_operation_t;

	signal expected_result : MATH_WORD;

	signal has_run : std_logic := '0';

	signal prev_enable_math : std_logic;
begin
	default clock is rising_edge(clk);

	process(clk)
	begin
		if rising_edge(clk) then
			prev_a <= a;
			prev_b <= b;
			prev_operation <= operation;
			prev_enable_math <= enable_math;
		end if;
	end process;

	-- assume inputs won't change while calculation is ongoing
	assume always not valid -> (
		a = prev_a and
		b = prev_b and
		operation = prev_operation
	);

	-- assume the "run" input is active at least until the result is valid
	assume always prev_enable_math -> (enable_math or valid);

	process(clk)
	begin
		if rising_edge(clk) and enable_math = '1' and valid = '1' then
			has_run <= '1';

			expected_result <= (others => '0');
			case operation is
				when ALU_AND =>
					expected_result <= a and b;
				when ALU_OR =>
					expected_result <= a or b;
				when ALU_XOR =>
					expected_result <= a xor b;
				when ALU_SHIFTL =>
					expected_result <= std_logic_vector(shift_left(
						unsigned(a),
						to_integer(unsigned(b(4 downto 0)))
					));
				when ALU_SHIFTR_L =>
					expected_result <= std_logic_vector(shift_right(
						unsigned(a),
						to_integer(unsigned(b(4 downto 0)))
					));
				when ALU_SHIFTR_A =>
					expected_result <= std_logic_vector(shift_right(
						signed(a),
						to_integer(unsigned(b(4 downto 0)))
					));
				when ALU_ADD =>
					expected_result <= std_logic_vector(signed(a) + signed(b));
				when ALU_SUB =>
					expected_result <= std_logic_vector(signed(a) - signed(b));
			end case;
		end if;
	end process;

	-- When a result has been computed, it must be correct
	assert always valid and has_run -> math_result = expected_result;
	-- Eventually, a result will always be available
	assert always enable_math -> eventually! valid;

	-- Hints for induction
	assert always not valid -> enable_math;
	assert always not valid and (
		operation = ALU_SHIFTL or
		operation = ALU_SHIFTR_L or
		operation = ALU_SHIFTR_A) -> not (or current_b(current_b'left downto 5));
end block;
