-- ALU


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;


entity ALU is
   generic ( N : in integer := 8);
   port (
      A, B	: in std_logic_vector(N-1 downto 0);
      OP	: in std_logic_vector(3 downto 0);
      Cin	: in std_logic;
      Cout, OVF	: out std_logic;
      Z		: out std_logic_vector(N-1 downto 0));
end ALU;


architecture RTL of ALU is

--   signal A, B	: std_logic_vector(N-1 downto 0);
   
subtype unsigned is std_logic_vector;

begin

proc : process (A, B, Cin, OP)
   variable temp1, temp2, result : unsigned(N downto 0);
begin
   Z	<= (Z'range => '0');
   Cout	<= '0';
   OVF <= '0';
 --  A <= (A'range => '0');
 --  B <= (B'range => '0');
 --  Cin <= '0';
   result := (result'range => '0');
   temp1  := (temp1'range => '0');
   temp2  := (temp2'range => '0');
 -- zakladni operace
 -- logicke operace nebude carry ovlivnovat
   case OP is
	when "0000" => Z <= (Z'range => Cin);
	when "0001" => Z <= A and B;
	when "0010" => Z <= A or B;
	when "0011" => Z <= not A;
	when "0100" => Z <= not B;
	when "0101" => Z <= A xor B;
	when "0110" => Z <= A nand B;
	when "0111" => Z <= A nor B;
	when others => null;
   end case;

 -- ALU pouziva doplnkovy kod
   temp1 := '0' & unsigned(A);
   --plne operandy musi byt prvni
   if OP = "1000" then -- => Z <= A-B+Cin;
     temp2 := '0' & unsigned(B);
     result := temp1 - temp2 + Cin;
     OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) or ((temp1(N-1) and temp2(N-1)) and not(result(N-1));
     -- OVF <= (temp1(N-1) xor temp2(N-1)) and (temp1(N-1) xor result(N-1));
     Z <= result((N-1) downto 0);
   elsif OP = "1100" then -- => Z <= A-B-Cin;
     temp2 := '0' & unsigned(B);
     result := temp1 - temp2 - Cin;
     OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) or ((temp1(N-1) and temp2(N-1)) and not(result(N-1));
     -- OVF <= (temp1(N-1) xor temp2(N-1)) and (temp1(N-1) xor result(N-1));
     Z <= result((N-1) downto 0);   
   elsif OP(3 downto 2) = "10" then -- + Cin 
     case OP(1 downto 0) is -- scitani
	when "01" => -- Z <= A+B+Cin;
	   temp2 := '0' & unsigned(B);
	when "10" => -- Z <= A+A+Cin;
	   temp2 := '0' & unsigned(A);
	when "11" => -- Z <= A+Cin;
	   temp2 := (temp2'range => '0');
	when others => null;
     end case;
     result := temp1 + temp2 + Cin;
     OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) or ((temp1(N-1) and temp2(N-1)) and not(result(N-1));
     -- OVF <= ((not (temp1(N-1) xor temp2(N-1))) and (temp1(N-1) xor result(N-1)));
		-- (temp1((N-1)) xor result((N-1)));
     Z <= result((N-1) downto 0);
   elsif OP(3 downto 2) = "11" then -- -Cin
     case OP(1 downto 0) is
	when "01" => -- Z <= A+B-Cin;
	   temp2 := '0' & unsigned(B);
	when "10" => -- Z <= A+A-Cin;
	   temp2 := '0' & unsigned(A);
	when "11" => -- Z <= A-Cin;
	   temp2 := (temp2'range => '0');
	when others => null;
     end case;
     result := temp1 + temp2 - Cin;
     OVF <= ((not(temp1(N-1)) and not(temp2(N-1))) and result(N-1)) or ((temp1(N-1) and temp2(N-1)) and not(result(N-1));
     -- OVF <= ((not (temp1(N-1) xor temp2(N-1))) and (temp1(N-1) xor result(N-1)));
		-- (temp1((N-1)) xor result((N-1)));
     Z <= result((N-1) downto 0);
   end if;

   Cout <= result(N);

end process;
end RTL;


-- testovani ALU

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity TestALU_B is
end TestALU_B;

architecture BEH of TestALU_B is

   component ALU
   generic ( N : in integer := 8);
   port (
	A, B	: in std_logic_vector(N-1 downto 0);
	OP	: in std_logic_vector(3 downto 0);
	Cin	: in std_logic;
	Cout, OVF	: out std_logic;
	Z	: out std_logic_vector(N-1 downto 0)
	);
   end component;
   constant PERIOD	: time := 20 ns;
   constant N		: integer := 8;
   signal A		: std_logic_vector((N - 1) downto 0);
   signal B		: std_logic_vector((N - 1) downto 0);
   signal S		: std_logic_vector(3 downto 0);
   signal Cin		: std_logic;
   signal Cout		: std_logic;
   signal OVF		: std_logic;
   signal Z		: std_logic_vector((N - 1) downto 0);
begin

   ALU0 : ALU
	generic map (N => N)
	port map (A => A, B => B, OP => S, Cin => Cin, Cout => Cout,
	OVF => OVF, Z => Z);

--   assert Cout = Cout1 report "Cout nesedni" severity NOTE;
--   assert OVF = OVF1 report "OVF nesedni" severity NOTE;
--   assert Z = Z1 report "Z nesedni" severity NOTE;
--   testproc : process
   process
	variable Aint : integer range 0 to 255 := 3;
	variable Bint : integer range 0 to 255 := 230;
   begin
	for i in 0 to 1 loop
	   Aint := (Aint + 5) mod 255;
	   Bint := (Bint + 53) mod 255;
	   A <= to_stdlogicvector(Aint, N);
	   B <= to_stdlogicvector(Bint, N);
	   if (i = 0) then
		Cin <= '0';
		for k in 0 to 15 loop
		   S <= to_stdlogicvector(k, 4);
		   wait for PERIOD;
		end loop;
	   else
		Cin <= '1';
		for k in 0 to 15 loop
		   S <= to_stdlogicvector(k, 4);
		   wait for PERIOD;
		end loop;
	   end if;
	end loop;
	wait for 2 * PERIOD;
   end process;
end BEH;

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

configuration BEH of TestALU_B is
   for BEH
	for ALU0 : ALU
	   use entity work.ALU(RTL);
	end for;
   end for;
end BEH;

