--
-- Copyright (c) 1999-2000 University of California, Riverside.
-- Permission to copy is granted provided that this header remains
-- intact.  This software is provided with no warranties.
--
-- Version : 1.0
--

-------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use WORK.I8051_LIB.all;

-------------------------------------------------------------------------------

entity I8051_ALU is
    port(rst     : in  STD_LOGIC;
         op_code : in  UNSIGNED (3 downto 0);
         src_1   : in  UNSIGNED (7 downto 0);
         src_2   : in  UNSIGNED (7 downto 0);
         src_3   : in  UNSIGNED (7 downto 0);
         src_cy  : in  STD_LOGIC;
         src_ac  : in  STD_LOGIC;
         des_1   : out UNSIGNED (7 downto 0);
         des_2   : out UNSIGNED (7 downto 0);
         des_cy  : out STD_LOGIC;
         des_ac  : out STD_LOGIC;
         des_ov  : out STD_LOGIC);
end I8051_ALU;

-------------------------------------------------------------------------------

architecture BHV of I8051_ALU is

-------------------------------------------------------------------------------

    procedure PCSADD (a : UNSIGNED (15 downto 0);
                      b : UNSIGNED (7 downto 0);
                      r : out UNSIGNED (15 downto 0)) is

        variable v1, v2 : SIGNED (15 downto 0);
    begin
        v1 := SIGNED(a);
        if( b(7) = '1' ) then
            
            v2 := SIGNED(CM_8 & b);
        else
            
            v2 := SIGNED(C0_8 & b);
        end if;
        v1 := v1 + v2;
        r := UNSIGNED(v1);
    end PCSADD;

-------------------------------------------------------------------------------
        
    procedure PCUADD (a : UNSIGNED (15 downto 0);
                      b : UNSIGNED (7 downto 0);
                      r : out UNSIGNED (15 downto 0)) is
    begin
        r := a + b;
    end PCUADD;
    
-------------------------------------------------------------------------------

    procedure DO_ADD (a, b : in  UNSIGNED (7 downto 0);
                      c : in  STD_LOGIC;
                      r : out UNSIGNED (7 downto 0);
                      cy, ac, ov : out STD_LOGIC) is
        
        variable v1, v2, v3, v4 : UNSIGNED (4 downto 0);
        variable v5, v6, v7, v8 : UNSIGNED (3 downto 0);
        variable v9, vA, vB, vC : UNSIGNED (1 downto 0);
    begin

        v1 := "0" & a(3 downto 0);
        v2 := "0" & b(3 downto 0);
        v3 := "0" & "000" & c;
        v4 := v1 + v2 + v3;
        
        v5 := "0" & a(6 downto 4);
        v6 := "0" & b(6 downto 4);
        v7 := "0" & "00" & v4(4);
        v8 := v5 + v6 + v7;

        v9 := "0" & a(7);
        vA := "0" & b(7);
        vB := "0" & v8(3);
        vC := v9 + vA + vB;
        
        r(7) := vC(0);
        r(6) := v8(2);
        r(5) := v8(1);
        r(4) := v8(0);
        r(3) := v4(3);
        r(2) := v4(2);
        r(1) := v4(1);
        r(0) := v4(0);
        cy := vC(1);
        ac := v4(4);
        ov := vC(1) xor v8(3);
    end DO_ADD;

-------------------------------------------------------------------------------
    
    procedure DO_SUB (a, b : in  UNSIGNED (7 downto 0);
                      c : in  STD_LOGIC;
                      r : out UNSIGNED (7 downto 0);
                      cy, ac, ov : out STD_LOGIC) is

        variable v1, v2, v3, v4 : UNSIGNED (4 downto 0);
        variable v5, v6, v7, v8 : UNSIGNED (3 downto 0);
        variable v9, vA, vB, vC : UNSIGNED (1 downto 0);
    begin

        v1 := "1" & a(3 downto 0);
        v2 := "0" & b(3 downto 0);
        v3 := "0" & "000" & c;
        v4 := v1 - v2 - v3;
        
        v5 := "1" & a(6 downto 4);
        v6 := "0" & b(6 downto 4);
        v7 := "0" & "00" & (not v4(4));
        v8 := v5 - v6 - v7;

        v9 := "1" & a(7);
        vA := "0" & b(7);
        vB := "0" & (not v8(3));
        vC := v9 - vA - vB;
        
        r(7) := vC(0);
        r(6) := v8(2);
        r(5) := v8(1);
        r(4) := v8(0);
        r(3) := v4(3);
        r(2) := v4(2);
        r(1) := v4(1);
        r(0) := v4(0);
        cy := not vC(1);
        ac := not v4(4);
        ov := (not vC(1)) xor (not v8(3));
    end DO_SUB;

-------------------------------------------------------------------------------

    procedure DO_MUL(a, b : in UNSIGNED (7 downto 0);
                     r : out UNSIGNED (15 downto 0);
                     ov : out STD_LOGIC) is

        variable v1 : UNSIGNED (15 downto 0);
    begin
        v1 := a * b;
        r := v1;
        if( v1(15 downto 8) /= C0_8 ) then

            ov := '1';
        else
            
            ov := '0';
        end if;
    end DO_MUL;
    
-------------------------------------------------------------------------------

    procedure DO_DIV(a, b : in UNSIGNED (7 downto 0);
                     r : out UNSIGNED (15 downto 0);
                     ov : out STD_LOGIC) is
    
        variable v1 : UNSIGNED (15 downto 0);
        variable v2, v3 : UNSIGNED (8 downto 0);
    begin
        if( b = C0_8 ) then
            
            r(7 downto 0) := CD_8;
            r(15 downto 8) := CD_8;
            ov := '1';
        elsif( a = b ) then

            r(7 downto 0) := C1_8;
            r(15 downto 8) := C0_8;
            ov := '0';
        elsif( a < b ) then

            r(7 downto 0) := C0_8;
            r(15 downto 8) := src_1;
            ov := '0';
        else

            v1(7 downto 0) := a;
            v1(15 downto 8) := C0_8;
            v3 := "0" & b;
            for i in 0 to 7 loop

                v1(15 downto 1) := v1(14 downto 0);
                v1(0) := '0';
                v2 := "1" & v1(15 downto 8);
                v2 := v2 - v3;
                if( v2(8) = '1' ) then
                    
                    v1(0) := '1';
                    v1(15 downto 8) := v2(7 downto 0);
                end if;
            end loop;

            r := v1;
            ov := '0';
        end if;
    end DO_DIV;
    
-------------------------------------------------------------------------------

    procedure DO_DA(a : in UNSIGNED (7 downto 0);
                    c1, c2 : in STD_LOGIC;
                    r : out UNSIGNED (7 downto 0);
                    cy : out STD_LOGIC) is

        variable v : UNSIGNED (8 downto 0);
    begin

        v := "0" & a;
        if( (c2 = '1') or (v(3 downto 0) > C9_4) ) then

            v := v + "000000110";
        end if;
        
        v(8) := v(8) or c1;
        
        if( v(8) = '1' ) then

            v := v + "001100000";
        end if;
        
        r := v(7 downto 0);
        cy := v(8);
    end DO_DA;

-------------------------------------------------------------------------------

begin
    process(rst, op_code, src_1, src_2, src_3, src_cy, src_ac)

        variable v16 : UNSIGNED (15 downto 0);
        variable v8 : UNSIGNED (7 downto 0);
        variable v_cy, v_ac, v_ov : STD_LOGIC;
    begin
        if( rst = '1' ) then

            des_1 <= CD_8;
            des_2 <= CD_8;
            des_cy <= '-';
            des_ac <= '-';
            des_ov <= '-';
        else

            case op_code is
                when ALU_OPC_ADD    =>
                    DO_ADD(src_1, src_2, src_cy, v8, v_cy, v_ac, v_ov);
                    des_1 <= v8;
                    des_2 <= CD_8;
                    des_cy <= v_cy;
                    des_ac <= v_ac;
                    des_ov <= v_ov;
                    
                when ALU_OPC_SUB    =>
                    DO_SUB(src_1, src_2, src_cy, v8, v_cy, v_ac, v_ov);
                    des_1 <= v8;
                    des_2 <= CD_8;
                    des_cy <= v_cy;
                    des_ac <= v_ac;
                    des_ov <= v_ov;

                when ALU_OPC_MUL    =>
                    DO_MUL(src_1, src_2, v16, v_ov);
                    des_1 <= v16(7 downto 0);
                    des_2 <= v16(15 downto 8);
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= v_ov;
                    
                when ALU_OPC_DIV    =>
                    DO_DIV(src_1, src_2, v16, v_ov);
                    des_1 <= v16(7 downto 0);
                    des_2 <= v16(15 downto 8);
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= v_ov;
                    
                when ALU_OPC_DA     =>
                    DO_DA(src_1, src_cy, src_ac, v8, v_cy);
                    des_1 <= v8;
                    des_2 <= CD_8;
                    des_cy <= v_cy;
                    des_ac <= '-';
                    des_ov <= '-';

                when ALU_OPC_NOT    =>
                    des_1(7) <= not src_1(7);
                    des_1(6) <= not src_1(6);
                    des_1(5) <= not src_1(5);
                    des_1(4) <= not src_1(4);
                    des_1(3) <= not src_1(3);
                    des_1(2) <= not src_1(2);
                    des_1(1) <= not src_1(1);
                    des_1(0) <= not src_1(0);
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';

                when ALU_OPC_AND    =>
                    des_1(7) <= src_1(7) and src_2(7);
                    des_1(6) <= src_1(6) and src_2(6);
                    des_1(5) <= src_1(5) and src_2(5);
                    des_1(4) <= src_1(4) and src_2(4);
                    des_1(3) <= src_1(3) and src_2(3);
                    des_1(2) <= src_1(2) and src_2(2);
                    des_1(1) <= src_1(1) and src_2(1);
                    des_1(0) <= src_1(0) and src_2(0);
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';
                    
                when ALU_OPC_XOR    =>
                    des_1(7) <= src_1(7) xor src_2(7);
                    des_1(6) <= src_1(6) xor src_2(6);
                    des_1(5) <= src_1(5) xor src_2(5);
                    des_1(4) <= src_1(4) xor src_2(4);
                    des_1(3) <= src_1(3) xor src_2(3);
                    des_1(2) <= src_1(2) xor src_2(2);
                    des_1(1) <= src_1(1) xor src_2(1);
                    des_1(0) <= src_1(0) xor src_2(0);
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';

                when ALU_OPC_OR     =>
                    des_1(7) <= src_1(7) or src_2(7);
                    des_1(6) <= src_1(6) or src_2(6);
                    des_1(5) <= src_1(5) or src_2(5);
                    des_1(4) <= src_1(4) or src_2(4);
                    des_1(3) <= src_1(3) or src_2(3);
                    des_1(2) <= src_1(2) or src_2(2);
                    des_1(1) <= src_1(1) or src_2(1);
                    des_1(0) <= src_1(0) or src_2(0);
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';

                when ALU_OPC_RL     =>
                    des_1(0) <= src_1(7);
                    des_1(7 downto 1) <= src_1(6 downto 0);
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';
                     
                when ALU_OPC_RLC    =>
                    des_1(0) <= src_cy;
                    des_1(7 downto 1) <= src_1(6 downto 0);
                    des_2 <= CD_8;
                    des_cy <= src_1(7);
                    des_ac <= '-';
                    des_ov <= '-';

                when ALU_OPC_RR     =>
                    des_1(7) <= src_1(0);
                    des_1(6 downto 0) <= src_1(7 downto 1);
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov<= '-';

                when ALU_OPC_RRC    =>
                    des_1(7) <= src_cy;
                    des_1(6 downto 0) <= src_1(7 downto 1);
                    des_2 <= CD_8;
                    des_cy <= src_1(0);
                    des_ac <= '-';
                    des_ov <= '-';

                when ALU_OPC_PCSADD =>
                    PCSADD(src_2 & src_1, src_3, v16);
                    des_1 <= v16(7 downto 0);
                    des_2 <= v16(15 downto 8);
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';
                    
                when ALU_OPC_PCUADD =>
                    PCUADD(src_2 & src_1, src_3, v16);
                    des_1 <= v16(7 downto 0);
                    des_2 <= v16(15 downto 8);
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';

                when others         =>
                    des_1 <= CD_8;
                    des_2 <= CD_8;
                    des_cy <= '-';
                    des_ac <= '-';
                    des_ov <= '-';
            end case;
        end if;
    end process;
end BHV;

<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>