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

entity alu is
  port(
        a: in std_logic_vector(15 downto 0);
        b: in std_logic_vector(15 downto 0);
        sel: in std_logic_vector(3 downto 0);

        flag: out std_logic;
        q: out std_logic_vector(15 downto 0)
      );
end alu;

architecture behavior of alu is
begin

process(a, b, sel) is
  variable tmp: std_logic_vector(31 downto 0);
  variable idx: natural;
begin

  q <= x"0000";
  flag <= '0';
  tmp := x"00000000";
  idx := 0;

  case sel is
    when "0011" => -- q = a + b, flag is carry
      tmp(16 downto 0) := std_logic_vector(unsigned('0' & a) + unsigned(b));
      q <= tmp(15 downto 0);
      flag <= tmp(16);
    when "0100" => -- q = a - b, flag if a < b
      tmp(16 downto 0) := std_logic_vector(unsigned('1' & a) - unsigned(b));
      q <= tmp(15 downto 0);
      flag <= not tmp(16);
    when "0101" => q <= a or b;
    when "0110" => q <= a and b;
    when "0111" => q <= not a;
    when "1000" => q <= a xor b;
    when "1001" => -- left shift by 1
      q <= a(14 downto 0) & '0';
      flag <= a(15);
    when "1010" => -- right shift by b(3 downto 0)
      idx := to_integer(unsigned(b(3 downto 0)));
      tmp(15 - idx downto 0) := a(15 downto idx);
      q <= tmp(15 downto 0);
      flag <= a(0);
    when "1011" => -- q = a * b
      --tmp := std_logic_vector(unsigned(a) * unsigned(b));
      q <= tmp(15 downto 0);
    when "1100" => -- flag if a = b
      if (a = b) then
        flag <= '1';
      else
        flag <= '0';
      end if;

    --- room for a few more things:
    -- - rotate
    -- - not / nand
    -- - gt...

    when others =>
  -- do nothing
  end case;
end process;

end behavior;
