----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Jim Plusquellic
-- 
-- Create Date:    16:04:58 09/23/2009 
-- Design Name: 
-- Module Name:    AddUnit
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;

-- add_ins, sub_ins, skwlf_ins (skip is register w is less than f), and skwgf_ins are
-- instructions -- only 1 or 0 of them will be '1' at any given point in time.
-- A and B are the 12-bit input operands, ADD_OUT is the 12-bit result of the add or
-- subtract. skw_success is set to '1' if the result of the compare instructions is
-- true
entity AddUnit is
   port(
      add_ins, sub_ins, skwlf_ins, skwgf_ins : std_logic;
      A, B : in std_logic_vector(11 downto 0);
      ADD_OUT : out std_logic_vector(11 downto 0);
      skw_success : out std_logic;
      carry_out : out std_logic
   );
end entity;

architecture beh of AddUnit is

-- ripple is used to connect the carry_out to the carry_in of the next higher full adder
   signal ripple : std_logic_vector(10 downto 0);
   signal B_op, result : std_logic_vector(11 downto 0);
   signal one_hot_ins : std_logic_vector(3 downto 0);
   signal do_sub : std_logic_vector(2 downto 0);
   signal skw_suc_lf, not_all_zero, skw_suc_gf : std_logic;
   signal carry_in : std_logic;
   begin

-- set carry_in to '1' and XOR the B operand bits with 1 (invert them) if the instruction 
-- is one of either sub_ins, skwlf_ins or skwgf_ins
   do_sub <= sub_ins & skwlf_ins & skwgf_ins; 
   with do_sub select
      carry_in <= '0' when "000",
                  '1' when others;
   with do_sub select
      B_op <= B when "000",
              (B xor "111111111111") when others;

-- instantiate 12 copies of the full_adder and wire them to implement 12 bit adder. Note
-- that carry_out of the full adder of a lower order bit is used as carry_in in the full 
-- adder computing the sum for the higher order bit.
   FA0: entity work.FullAdder(beh)
      port map (a=>A(0), b=>B_op(0), carry_in=>carry_in, sum_out=>result(0), carry_out=>ripple(0));
   FA1: entity work.FullAdder(beh)
      port map (a=>A(1), b=>B_op(1), carry_in=>ripple(0), sum_out=>result(1), carry_out=>ripple(1));
   FA2: entity work.FullAdder(beh)
      port map (a=>A(2), b=>B_op(2), carry_in=>ripple(1), sum_out=>result(2), carry_out=>ripple(2));
   FA3: entity work.FullAdder(beh)
      port map (a=>A(3), b=>B_op(3), carry_in=>ripple(2), sum_out=>result(3), carry_out=>ripple(3));
   FA4: entity work.FullAdder(beh)
      port map (a=>A(4), b=>B_op(4), carry_in=>ripple(3), sum_out=>result(4), carry_out=>ripple(4));
   FA5: entity work.FullAdder(beh)
      port map (a=>A(5), b=>B_op(5), carry_in=>ripple(4), sum_out=>result(5), carry_out=>ripple(5));
   FA6: entity work.FullAdder(beh)
      port map (a=>A(6), b=>B_op(6), carry_in=>ripple(5), sum_out=>result(6), carry_out=>ripple(6));
   FA7: entity work.FullAdder(beh)
      port map (a=>A(7), b=>B_op(7), carry_in=>ripple(6), sum_out=>result(7), carry_out=>ripple(7));
   FA8: entity work.FullAdder(beh)
      port map (a=>A(8), b=>B_op(8), carry_in=>ripple(7), sum_out=>result(8), carry_out=>ripple(8));
   FA9: entity work.FullAdder(beh)
      port map (a=>A(9), b=>B_op(9), carry_in=>ripple(8), sum_out=>result(9), carry_out=>ripple(9));
   FA10: entity work.FullAdder(beh)
      port map (a=>A(10), b=>B_op(10), carry_in=>ripple(9), sum_out=>result(10), carry_out=>ripple(10));
   FA11: entity work.FullAdder(beh)
      port map (a=>A(11), b=>B_op(11), carry_in=>ripple(10), sum_out=>result(11), carry_out=>carry_out);

-- Determine the value of skw_success. If skwlf_ins is '1', then set skw_success if MSB of adder is '1'.
-- (A - B) is negative, therefore A is less than B. 
   skw_suc_lf <= skwlf_ins and result(11);

-- If skwgf_ins is '1', then set skw_success if MSB of adder is '0' AND there is at least 1 '1' in
-- the low order bits
   not_all_zero <= result(0) or result(1) or result(2) or result(3) or result(4) or result(5) or 
      result(6) or result(7) or result(8) or result(9) or result(10);
   skw_suc_gf <= skwgf_ins and not result(11) and not_all_zero;

-- skw_success is the or of the two conditions
   skw_success <= skw_suc_lf or skw_suc_gf;

-- Tri-state the output. First create a vector of the four instructions (remember, they are one-hot
-- or zero-hot)
   one_hot_ins <= add_ins & sub_ins & skwlf_ins & skwgf_ins;

-- If none of the instructions are '1', then set ADD_OUT to 'Z's (un-driven), otherwise set ADD_OUT
-- to the output vector of the 12-bit adder.
   with one_hot_ins select
      ADD_OUT <= (others => 'Z') when "0000",
                 result when others;

end beh; 
