------------------------------------------------------------
-- Copyright Mentor Graphic Corporation 1991. 
-- All rights reserved.  
------------------------------------------------------------
--
--  Model Title: Execution Unit for Microprocessor "EX-1"
--  Date Created: 95/10/25 (WED)
--  Author:       T. Ohtsuka
--
------------------------------------------------------------
-- Model Description: 
--
-----------------------------------------------------------
--
LIBRARY IEEE,ARITHMETIC ;
LIBRARY work ;

USE IEEE.STD_LOGIC_1164.ALL ;
USE ARITHMETIC.STD_LOGIC_ARITH.ALL ;

ENTITY eu IS
   PORT (
         clk1              :  IN    STD_LOGIC ;
                              -- phase I clock
--         clk2              :  IN    STD_LOGIC ;
                              -- phase II clock
         a                 :  IN    STD_LOGIC_VECTOR(7 DOWNTO 0);
                              -- A port of the ALU input
         b                 :  IN    STD_LOGIC_VECTOR(7 DOWNTO 0) ;
                              -- B port of the ALU input
         c_ctl             :  IN    STD_LOGIC_VECTOR(2 DOWNTO 0) ;
                              -- CARRY control
         acc_msb           :  IN    STD_LOGIC ;
                              -- MSB of ACC
         acc_lsb           :  IN    STD_LOGIC ;
                              -- LSB of ACC
         add_with_carry    :  IN    STD_LOGIC ;
                              -- add with carry control
         sub_with_borrow   :  IN    STD_LOGIC ;
                              -- substraction with borrow control
         alu_f_ctl         :  IN    STD_LOGIC_VECTOR(4 DOWNTO 0) ;
                              -- function control fo ALU
         zfc_acc_on        :  IN    STD_LOGIC ;
                              -- ZERO flag control for ACC value
         zfc_alu_on        :  IN    STD_LOGIC ;
                              -- ZERO flag control for ALU value
         zfc_acc           :  IN    STD_LOGIC ;
                              -- ZERO flag control for the result of shift/rotate in ACC
         alu               :  OUT   STD_LOGIC_VECTOR(7 DOWNTO 0) ;
                              -- the output of ALU
         carry             :  OUT   STD_LOGIC ;
                              -- output of CARRY flag register
         zero              :  OUT   STD_LOGIC
                              -- output of ZERO flag register
        ) ;
END eu ;

ARCHITECTURE behave OF eu IS
 
SIGNAL c0,c1   : STD_LOGIC ; 
  -- c0 is output of carry flag reg. 
  -- c1 is the carry output of ALU, which is a combinational circuit.
SIGNAL z_alu   : STD_LOGIC ;
  -- z_alu is zero flag of the result of ALU.
SIGNAL alu_ctl : STD_LOGIC_VECTOR(6 DOWNTO 0) ;
  -- Input port of ALU with the overflow bits
SIGNAL a9, b9, result   : STD_LOGIC_VECTOR(8 DOWNTO 0) ;
  -- a9 is the A port of ALU with overflow bit ( a9(8) )
  -- b9 is the B port of ALU with overflow bit ( b9(8) )
  -- result is the output of ALU with carry output ( result(8) )
BEGIN

  -- select the ALU functional
  alu_ctl <= alu_f_ctl & add_with_carry & sub_with_borrow ;
  a9 <= "0" & a ;   -- insert the overflow bit
  b9 <= "0" & b ;   -- insert overflow bit

  WITH  alu_ctl SELECT
     -- transfer the A port data to the result.
     result <= a9 AFTER 100 ns WHEN "0000000" ,
     -- increment the A port data.
            a9 + "000000001" AFTER 100 ns WHEN "0000011" ,
     -- decrement the A port data.
            a9 - "000000001" AFTER 100 ns WHEN "1111111" ,
     -- transfer the A port data to the result.
            b9  AFTER 100 ns WHEN "1101000" ,
     -- add A port data and B port data witouth carry.
            a9 + b9 AFTER 100 ns WHEN "0100100" ,
     -- add A port data and B port data with carry;
            a9 + b9 + ("0000000" & c0) AFTER 100 ns WHEN "0100110" ,
     -- substract B port data from B port data without borrow.
            a9 - b9  AFTER 100 ns WHEN "0011000" ,
     -- substract B port data from B port data with borrow.
            a9 - b9 + NOT ("0000000" & c0) AFTER 100 ns WHEN "0011001" ,
     -- AND
            a9 AND b9 AFTER 100 ns WHEN "1101100" ,
     -- OR
            a9 OR b9 AFTER 100 ns WHEN "1111000" ,
     -- XOR
            a9 XOR b9 AFTER 100 ns WHEN "1011000" ,
     -- clear
            "XXXXXXXXX" AFTER 100 ns WHEN OTHERS ;
   WITH alu_ctl SELECT
      c1 <= result(8) AFTER 100 ns WHEN "0000011",
            result(8) AFTER 100 ns WHEN "1111111",
            result(8) AFTER 100 ns WHEN "1101000",
            result(8) AFTER 100 ns WHEN "0100100",
            result(8) AFTER 100 ns WHEN "0100110",
            result(8) AFTER 100 ns WHEN "0011000",
            result(8) AFTER 100 ns WHEN "0011001",
            'X' AFTER 100 ns WHEN OTHERS ;
   alu <= result(7 DOWNTO 0) ;
     -- to wait until the data become available through the bus
     -- that is expected to be implemented by 74LS541.
   z_alu <= result(0) OR result(1) OR result(2) OR result(3) OR 
            result(4) OR result(5) OR result(6) OR result(7) ;

  carry_flag_reg : PROCESS(clk1)
   -- the process of the CARRY flag register

  BEGIN
     IF ((clk1 = '1') AND (clk1'LAST_VALUE = '0') AND clk1'EVENT) THEN
        -- edge triggered
        -- carry flag control
        CASE c_ctl IS
           WHEN "011"  => c0 <= '0' ;   -- clear carry
           WHEN "100"  => c0 <= '1' ;   -- set carry
           WHEN "101"  => c0 <= acc_lsb ;  -- shift/rotate right
           WHEN "110"  => c0 <= acc_msb ;  -- shift/rotate left
           WHEN "000"  => c0 <= c0 ;
           WHEN "001"  => c0 <= c1 ;
           WHEN OTHERS => c0 <= c0 ;
        END CASE ;
     END IF ;
  END PROCESS carry_flag_reg ;
  carry <= c0 ;

  zero_flag_reg : PROCESS(clk1)
   VARIABLE zfc      : STD_LOGIC_VECTOR(3 DOWNTO 0) ;
            -- ZERO flag control for values of ACC and ALU

  BEGIN
     IF ((clk1 = '1') AND (clk1'LAST_VALUE = '0') AND clk1'EVENT) THEN
        zfc := zfc_acc_on & zfc_alu_on & z_alu & zfc_acc ;
        -- zero flag control
        CASE zfc IS
           -- ALU zero flag mode
           WHEN "0100" => zero <= '1' ;
           WHEN "0101" => zero <= '1' ;
           WHEN "0110" => zero <= '0' ;
           WHEN "0111" => zero <= '0' ;
           -- ACC zero flag mode
           WHEN "1001" => zero <= '1' ;
           WHEN "1011" => zero <= '1' ;
           WHEN "1000" => zero <= '0' ;
           WHEN "1010" => zero <= '0' ;
           -- etc.
           WHEN OTHERS => NULL ;
        END CASE ;
     END IF ;
  END PROCESS zero_flag_reg ;

END behave ;