-- TITLE:
-----------------------------------------------------------------
-- VHDL code for the ALU:(leaf cell, lowest hierarchy)         --
-----------------------------------------------------------------
-- Description: Currently the case statements depend on the   --
--             opcode and subOP values the controller encoding --
--             will change these when it is seriously 
--             implemented.                			   --
--              								   --
--              								   --
-----------------------------------------------------------------
-- Course: Computer Architecture Project #2                    --
-----------------------------------------------------------------
-- Date | Begin: 12.05.2001                                    --
--      | End  : 12.05.2001                                    --
-----------------------------------------------------------------
-- Additional Comments:                                        --
--                                                             --
-----------------------------------------------------------------

-- ACCESSING DESIGN LIBRARIES and PACKAGES:
-------------------------------------------

---Library Clause: (Makes the written libraries visible to the design unit)
library ieee,work;
--library arithmetic ???? doesn't exist???
----ieee & arithmetic are predefined resource libraries
----none are user defined resource libraries
----work is working(design) library (there can be only 1!!)

---use clause: ( Specifies Which packages/declarations within a package are
---             required by the design unit
--use arithmetic.std_logic_arith.ALL;
use ieee.std_logic_1164.all;
--use ieee.std_logic_arith.all;
use ieee.numeric_std.all;
--> library.package.contents of package(constants,components,etc.)
------------------------------------------------------------------------------

--ENTITY DECLARATION and PORT MAP: (Interface of design unit to external env.)
----------------------------------

entity ALU64 is       -- ALU64: name of entity
                      -- entity name must be unique in the design library!!
  port (Op1      :  in  std_logic_vector(63 downto 0); -- Op1 i/p of ALU
        Op2    :  in  std_logic_vector(63 downto 0); -- Op2 i/p of ALU
        SubOP   :  in  std_logic_vector(7 downto 0);  -- SubOP portion (7:0) of 32 bit instr.
        Opcode :  in  std_logic_vector(5 downto 0);  -- comes from controller, BITWIDTH arbitrarily assigned for now!!
        ALUout  :  out std_logic_vector(63 downto 0)); -- ALU64 o/p

end ALU64;
------------------------------------------------------------------------------

--ARCHITECTURE BODY: (Internal details, function of block)
--------------------

architecture behav of ALU64 is  -- behav: Architecture name,
                                -- ALU64 : entity name,
--Architecture name must be unique among architectures sharing same entity!!
---[0]Architecture Declarations (type definitions,

---[1]Object Declarations: (INternal signals & Set of interconnected components - for structural)
-----------------------------------------------------------------------------------------------------
--OPCODE definitions/controller encoding def-s (will change when controller comes to play
-----------------------------------------------------------------------------------------------------
constant add: std_logic_vector(5 downto 0) := "110000"; -- for packed add signed wrapping
									   --and packed add unsigned saturation 
                                                         --and for lotsa other things!!!!@@@@@
constant cmp: std_logic_vector(5 downto 0) := "001000"; -- for cmp    
-- constant loadi.lo anf loadi.hi
constant loadi_lo: std_logic_vector(5 downto 0) := "000101";
constant loadi_hi: std_logic_vector(5 downto 0) := "000100";
-- for the unimplemented mux.2.brcst
constant mux_2_brcst: std_logic_vector(5 downto 0) := "110011";
-- for load.8.update, load.8 and store.8.update
constant load_8_upd: std_logic_vector(5 downto 0) := "010111";    
constant load_8: std_logic_vector(5 downto 0) := "010011";
constant store_8_upd: std_logic_vector(5 downto 0) := "011111";

-----------------------------------------------------------------------------------------------------
--SubOP definitions {instr(7:2)} - w/o sw (without last 2 bits that define subword size)
-----------------------------------------------------------------------------------------------------
constant add_s_w: std_logic_vector(7 downto 2) := "000000"; -- add_signed_wrapping arithmetic
constant add_u_s: std_logic_vector(7 downto 2) := "000001"; -- add_unsigned_saturation arithmetic
constant add_s_s: std_logic_vector(7 downto 2) := "000010"; -- add_signed_saturation arithmetic
constant add_inc: std_logic_vector(7 downto 2) := "000011"; -- add_increment

-----------------------------------------------------------------------------------------------------
--Subword size definitions {instr(1:0)} - last 2 bits that define subword size
-----------------------------------------------------------------------------------------------------
constant sw1: std_logic_vector(1 downto 0) := "00"; -- sw size 1 byte
constant sw2: std_logic_vector(1 downto 0) := "01"; -- sw size 2 bytes
constant sw4: std_logic_vector(1 downto 0) := "10"; -- sw size 4 bytes
constant sw8: std_logic_vector(1 downto 0) := "11"; -- sw size 8 bytes

begin -- of architecture

  ---[2]Concurrent Assignment Statements: (For Dataflow)

  ---[3]Processes: (Set of sequential assignments - for behavioral)
  DoOperation: process (Op1,Op2,Opcode,SubOP)
  --- Process Declarations:
  begin --of process
    --- sequential statements:
    case Opcode is
      when add =>
        case SubOP(7 downto 2) is
          when add_s_w => -- burda super for loop ayari yapilir!! for i in 1 to sw gibi
            if SubOP(1 downto 0)=sw8 then
              ALUout <= std_logic_vector(signed(Op1) + signed(Op2)); -- we can do this arithmetic in in std_logic
            elsif SubOP(1 downto 0)=sw4 then
              ALUout(63 downto 32) <= std_logic_vector(signed(Op1(63 downto 32)) + signed(Op2(63 downto 32)));
              ALUout(31 downto 0)  <= std_logic_vector(signed(Op1(31 downto 0))  + signed(Op2(31 downto 0))); 
            elsif SubOP(1 downto 0)=sw2 then
              ALUout(63 downto 48) <= std_logic_vector(signed(Op1(63 downto 48)) + signed(Op2(63 downto 48)));
              ALUout(47 downto 32) <= std_logic_vector(signed(Op1(47 downto 32)) + signed(Op2(47 downto 32))); 
              ALUout(31 downto 16) <= std_logic_vector(signed(Op1(31 downto 16)) + signed(Op2(31 downto 16))); 
              ALUout(15 downto 0)  <= std_logic_vector(signed(Op1(15 downto 0))  + signed(Op2(15 downto 0))); 
            elsif SubOP(1 downto 0)=sw1 then
              ALUout(63 downto 56) <= std_logic_vector(signed(Op1(63 downto 56)) + signed(Op2(63 downto 56)));
              ALUout(55 downto 48) <= std_logic_vector(signed(Op1(55 downto 48)) + signed(Op2(55 downto 48))); 
              ALUout(47 downto 40) <= std_logic_vector(signed(Op1(47 downto 40)) + signed(Op2(47 downto 40))); 
              ALUout(39 downto 32)  <= std_logic_vector(signed(Op1(39 downto 32))  + signed(Op2(39 downto 32))); 
              ALUout(31 downto 24) <= std_logic_vector(signed(Op1(31 downto 24)) + signed(Op2(31 downto 24)));
              ALUout(23 downto 16) <= std_logic_vector(signed(Op1(23 downto 16)) + signed(Op2(23 downto 16))); 
              ALUout(15 downto 8) <= std_logic_vector(signed(Op1(15 downto 8)) + signed(Op2(15 downto 8))); 
              ALUout(7 downto 0)  <= std_logic_vector(signed(Op1(7 downto 0))  + signed(Op2(7 downto 0))); 
            else
      	      assert (false)  -- assert always
                report "Invalid subword size in add_signed_wrap Instruction!"
                severity WARNING;
            end if;
          when add_u_s => 
              -- BURDAN SOORASINI YAZMADIM!!!!!!!!!!!!!!!!!!!!!1
		      assert (false) -- assert always
                report "add_UNsigned_SAT Instruction!"
                severity WARNING;

          when others =>
            assert (false) -- assert always
                report "Invalid SubOP for add instruction!!"
                severity WARNING;
          end case;
      when cmp =>    
        case SubOP(3 downto 0) is
          when "0000" | "0001" => -- EQ or NEQ
            ALUout <= std_logic_vector(signed(Op1) - signed(Op2)); -- subtract the operands for compare logic
          when "0010" | "0011" | "0100" | "0101" => -- LT or LE or GT or GE 
            ALUout <= std_logic_vector(signed(Op1) - signed(Op2)); -- subtract the operands for compare logic
          when "0110" | "0111" | "1000" | "1001" => -- LTU or LEU or GTU or GEU 
            -- ALUout <= std_logic_vector(UNsigned(Op1) - UNsigned(Op2)); -- subtract the operands for compare logic
            -- ALUout <= std_logic_vector(to_signed(to_integer(unsigned(Op1))-to_integer(unsigned(Op2)),64));
            if signed(Op1)>=0 and signed(Op2)>=0 then
              ALUout <= std_logic_vector(UNsigned(Op1) - UNsigned(Op2));
            elsif signed(Op1)>=0 and signed(Op2)<0 then
              ALUout <= std_logic_vector(to_signed(-1,64));  -- give -1 as Op2 is bigger as unsigned
            elsif signed(Op1)<0 and signed(Op2)>=0 then
              ALUout <= std_logic_vector(to_signed(1,64)); -- give 1 as Op1 is bigger as unsigned
            elsif signed(Op1)<0 and signed(Op2)<0 then
              ALUout <= std_logic_vector(UNsigned(Op1) - UNsigned(Op2));
            end if;
          when others =>
            assert (false) -- assert always
                report "Invalid SubOP for CMP instruction!!"
                severity WARNING;
          end case;
      when loadi_lo =>
	    ALUout(63 downto 32) <= x"00000000";
	    ALUout(15 downto 0)  <= Op2(15 downto 0);
	    ALUout(31 downto 16) <= x"0000";
	  when loadi_hi =>
	    ALUout(63 downto 32) <= x"00000000";
	    ALUout(31 downto 16)  <= Op2(15 downto 0);
	    ALUout(15 downto 0) <= x"0000";	  
 	  when mux_2_brcst =>
	    ALUout <= Op1(15 downto 0)&Op1(15 downto 0)&Op1(15 downto 0)&Op1(15 downto 0); --repeat subwords
      when load_8_upd | load_8 | store_8_upd =>
        ALUout <= std_logic_vector(signed(Op1) + signed(Op2)); -- add Rs1 + imm13 assume the o/p is taken care of 
                                                               -- by the controller to be written back or not
   
--!! HERE MORE INSTRUCTIONS-->>                                                               
	  when others =>
		assert (false) -- assert always
                report "Invalid ALU function!!"
                severity WARNING;
      end case;  

  end process DoOperation; --EOProcess

end behav; --EOArchitecture
