-- Driver for the MC_adder lab #3. The four instructions add_ins_not, sub_ins_not and skwxx_not instructions
-- are one hots (connected to push buttons). skw_success_not is connected to LED 0 and address_out_not
-- is connected to LED 1. add_out is NOT connected to any FPGA pins yet

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity MC_Adder_Driver is
   Port ( 
      clk : in STD_LOGIC;
      reset : in STD_LOGIC;
      select_low_pair_not: in STD_LOGIC;
      add_ins_not : in  STD_LOGIC;
      sub_ins_not : in  STD_LOGIC;
      skwlf_ins_not : in  STD_LOGIC;
      skwgf_ins_not : in  STD_LOGIC;
      skw_success_not : out  STD_LOGIC;
      address_out_not : out  STD_LOGIC;
      add_out : out STD_LOGIC_VECTOR (11 downto 0));
end MC_Adder_Driver;

architecture Behavioral of MC_Adder_Driver is

-- 2-D array declaration for holding the data values
   constant ADDR_WIDTH : natural := 2;
   constant DATA_WIDTH : natural := 12;
   type rom_type is array (0 to 2**ADDR_WIDTH-1) of
      std_logic_vector(DATA_WIDTH-1 downto 0);
   signal adder_constants: rom_type; 

-- If we use this, XST optimizes the design eliminating the ROMs
--   constant adder_constants: rom_type := (
--      "000000000001", 
--      "111111111111",
--      "000000000001", 
--      "000000000010"
--      );

   signal arr_index1, arr_index2 : integer;
   signal add_ins, sub_ins, skwlf_ins, skwgf_ins : STD_LOGIC;
   signal select_low_pair : STD_LOGIC;
   signal skw_success : STD_LOGIC;

   signal A : STD_LOGIC_VECTOR (11 downto 0);
   signal B : STD_LOGIC_VECTOR (11 downto 0);

-- Declare MC_adder
   component MC_adder
      Port ( 
         A : in  STD_LOGIC_VECTOR (11 downto 0);
         B : in  STD_LOGIC_VECTOR (11 downto 0);
         add_ins : in  STD_LOGIC;
         sub_ins : in  STD_LOGIC;
         skwlf_ins : in  STD_LOGIC;
         skwgf_ins : in  STD_LOGIC;
         add_out : out  STD_LOGIC_VECTOR (11 downto 0);
         skw_success : out  STD_LOGIC);
   end component;

   begin

-- Array of pairs of values to be manipulated for demo
   adder_constants <= (
      "000000000001", 
      "111111111111",
      "000000000001", 
      "000000000010"
      );

-- pushbuttons are active low (input wire is 1 when NOT pressed), so invert
-- all pushbutton values. Switches output a 0 when closed (UP) -- invert
-- so that down is 0 and up is 1.
   select_low_pair <= not select_low_pair_not;
   add_ins <= not add_ins_not;
   sub_ins <= not sub_ins_not;
   skwlf_ins <= not skwlf_ins_not;
   skwgf_ins <= not skwgf_ins_not;

-- Assign proper constants to access the elements in the pair of values from the array
   arr_index1 <= 0 when select_low_pair = '0' else 2;
   arr_index2 <= 1 when select_low_pair = '0' else 3;

-- Connect the ROM values to the inputs of the MCAdderUnit
   A <= adder_constants(arr_index1);
   B <= adder_constants(arr_index2);

-- Instantiate the MCAdderUnit
   MCAdderUnit: MC_adder 
      port map(A=>A, B=>B, add_ins=>add_ins, sub_ins=>sub_ins, 
         skwlf_ins=>skwlf_ins, skwgf_ins=>skwgf_ins, add_out=>add_out, skw_success=>skw_success); 

-- Set the output values -- LEDs are on when driven with a 0, so invert internal values
-- address indicator LED is OFF if we are accessing first pair (output a 1) and ON if 
-- second pair (output a 0)
   skw_success_not <= not skw_success;
   address_out_not <= not select_low_pair;

end Behavioral;
