-- ALU Top

-- Libraries
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.std_logic_signed.all;

entity ALU_Top is
	generic (
		clock_frequency	: integer := 50000000;	-- Input clock rate in Hz (100 MHz default)
		segment_refresh	: integer := 50000); 	-- Refresh rate in Hz
	port (
		ja 				    : out std_logic_vector(6 downto 0); -- seg out
		seg                 : out std_logic_vector(6 downto 0); -- on board seg     
		an                  : out std_logic_vector(3 downto 0);   -- on board transistors
		dp					: out std_logic; 
		dp_b                : out std_logic;
		digit_select		: out std_logic_vector(7 downto 0);
		one					: in std_logic;
		ten					: in std_logic;
		hundred				: in std_logic;
		start				: in std_logic;
		opcode				: in std_logic_vector(2 downto 0);
		sel					: in std_logic;
		add_sub				: in std_logic;
		--A_B_Display         : in std_logic;   -- dictates which value is displayed on on board display
		clk					: in std_logic);
end ALU_Top;

architecture behavior of ALU_Top is

-------------------------------------------------------------------------------
--	COMPONENTS
-------------------------------------------------------------------------------
-- ALU
component ALU_2
generic (
	bit_depth			: integer := 8);
port (
	opcode				: in std_logic_vector(2 downto 0);
	A					: in signed(2 * bit_depth - 1 downto 0);
	B					: in signed(2 * bit_depth - 1 downto 0);
	execute				: in std_logic;
	result				: out signed(2 * bit_depth - 1 downto 0));
end component;

-- on board display
component BASYS_7_seg
generic(
	input_clk_freq	: integer := 100000000;	-- Input clock rate in Hz
	refresh_rate 	: integer := 50000);    -- Refresh rate in Hz
port(
	-- 7 Segment Display Output
	seg 			: out std_logic_vector(6 downto 0);	
	-- 7 Segment Display Decimal Point
	dp				: out std_logic;
    -- Selects Digit	
	an				: out std_logic_vector(3 downto 0);
	-- Input segments 0 through 3
	seg0 			: in std_logic_vector(6 downto 0);
	seg1 			: in std_logic_vector(6 downto 0);
	seg2 			: in std_logic_vector(6 downto 0);
	seg3 			: in std_logic_vector(6 downto 0);
	-- Input decimal points
	in_dp			: in std_logic_vector(3 downto 0);
	-- Input Clock
	clk				: in std_logic);
end component;

-- Seg Display
component Seg_Display_16
generic(
	input_clk_freq	: integer := 100000000;	-- Input clock rate in Hz
	refresh_rate 	: integer := 50000);    -- Refresh rate in Hz
port(
	-- 7 Segment Display Output
	seg 			: out std_logic_vector(6 downto 0);	
	-- 7 Segment Display Decimal Point
	dp				: out std_logic;
    -- Selects Digit	
	an				: out std_logic_vector(7 downto 0);
	-- Input segments 0 through 3
	digit_1 		: in std_logic_vector(6 downto 0);
	digit_2 		: in std_logic_vector(6 downto 0);
	digit_3 		: in std_logic_vector(6 downto 0);
	digit_4 		: in std_logic_vector(6 downto 0);
	digit_5			: in std_logic_vector(6 downto 0);
	digit_6 		: in std_logic_vector(6 downto 0);
	digit_7 		: in std_logic_vector(6 downto 0);
	digit_8 		: in std_logic_vector(6 downto 0);
	-- Input decimal points
	-- in_dp			: in std_logic_vector(15 downto 0);
	-- Input Clock
	clk				: in std_logic);
end component;

-- BCD Display
component binary_bcd
generic(
		N: 							integer := 16);
    port(
        clk, reset: 				in std_logic;
        binary_in: 					in std_logic_vector(N-1 downto 0);
        bcd0, bcd1, bcd2, bcd3,
		bcd4, bcd5, bcd6			: out std_logic_vector(3 downto 0));
end component;

-- Hex to 7 seg
component Hex_to_7_Seg
port (
	seven_seg		: out std_logic_vector(6 downto 0);
	hex				: in std_logic_vector(3 downto 0));
end component;

-- Signed to SLV Converter
component Signed_to_SLV
generic(
	bit_depth		: integer := 12);
port(
	Signed_in		: in signed(bit_depth - 1 downto 0);
	SLV_out			: out std_logic_vector(bit_depth - 1 downto 0);
	neg 			: out std_logic);
end component;	

-------------------------------------------------------------------------------
--	SIGNALS & CONSTANTS
-------------------------------------------------------------------------------
signal A_input, B_input		: signed(23 downto 0) := (others => '0');
signal Result_out			: signed(23 downto 0) := (others => '0');

signal A_slv, B_slv				: std_logic_vector(23 downto 0) := (others => '0');
signal Result_slv					: std_logic_vector(23 downto 0) := (others => '0');

signal A_sign, B_sign, Result_sign		: std_logic_vector(6 downto 0) := "0000000";

signal dig_1	: std_logic_vector(6 downto 0) := "0000000";
signal dig_2	: std_logic_vector(6 downto 0) := "0000000";
signal dig_3	: std_logic_vector(6 downto 0) := "0000000";
signal dig_4	: std_logic_vector(6 downto 0) := "0000000";
signal dig_5	: std_logic_vector(6 downto 0) := "0000000";
signal dig_6	: std_logic_vector(6 downto 0) := "0000000";
signal dig_7	: std_logic_vector(6 downto 0) := "0000000";
signal dig_8	: std_logic_vector(6 downto 0) := "0000000";
signal dig_9	: std_logic_vector(6 downto 0) := "0000000";
signal dig_10	: std_logic_vector(6 downto 0) := "0000000";
signal dig_11	: std_logic_vector(6 downto 0) := "0000000";
signal dig_12	: std_logic_vector(6 downto 0) := "0000000";
signal dig_13	: std_logic_vector(6 downto 0) := "0000000";
signal dig_14	: std_logic_vector(6 downto 0) := "0000000";
signal dig_15	: std_logic_vector(6 downto 0) := "0000000";
signal dig_16	: std_logic_vector(6 downto 0) := "0000000";

signal A_bcd0, A_bcd1, A_bcd2, A_bcd3, A_bcd4, A_bcd5, A_bcd6 	: std_logic_vector(3 downto 0) := x"0";
signal B_bcd0, B_bcd1, B_bcd2, B_bcd3, B_bcd4, B_bcd5, B_bcd6 	: std_logic_vector(3 downto 0) := x"0";
signal R_bcd0, R_bcd1, R_bcd2, R_bcd3, R_bcd4, R_bcd5, R_bcd6	: std_logic_vector(3 downto 0) := x"0";

signal one_lead, ten_lead, hundred_lead, start_lead 			: std_logic := '0';
signal one_follow, ten_follow, hundred_follow, start_follow 	: std_logic := '0';
signal one_edge_start, ten_edge_start, hundred_edge_start, start_start			: std_logic := '0';

signal A_neg, B_neg, R_neg			: std_logic := '0';

signal reset	: std_logic := '0';
signal in_dp    : std_logic_vector(3 downto 0) := "1111";
signal basys_seg_1, basys_seg_2, basys_seg_3, basys_seg_4    : std_logic_vector(6 downto 0) := "0000000";

-------------------------------------------------------------------------------
--	DESIGN
-------------------------------------------------------------------------------
begin

dig_1 <= Result_sign;
dig_10 <= A_sign;
dig_13 <= B_sign;

-- ALU
ALU : ALU_2
generic map(12)
port map(opcode, A_input, B_input, start_start, Result_out);

-- Binary BCD's
-- BCD Display A
A_BCD: binary_bcd
	generic map(24)
	port map(clk, reset, A_slv, A_bcd0, A_bcd1, A_bcd2, A_bcd3, A_bcd4, A_bcd5, A_bcd6);
	
-- BCD Display B	
B_BCD: binary_bcd
	generic map(24)
	port map(clk, reset, B_slv, B_bcd0, B_bcd1, B_bcd2, B_bcd3, B_bcd4, B_bcd5, B_bcd6);

-- BCD Display Result
R_BCD: binary_bcd
	generic map(24)
	port map(clk, reset, Result_slv, R_bcd0, R_bcd1, R_bcd2, R_bcd3, R_bcd4, R_bcd5, R_bcd6);

-- Hex to 7 Seg converters
--DIGIT_1: Hex_to_7_Seg
--	port map(dig_1, Result_sign);

-- A Converter
A_CONVERTER: Signed_to_SLV
    generic map(24)
    port map(A_input, A_slv, A_neg);
    
B_CONVERTER: Signed_to_SLV
        generic map(24)
        port map(B_input, B_slv, B_neg);
        
RESULT_CONVERTER: Signed_to_SLV
            generic map(24)
            port map(Result_out, Result_slv, R_neg);            
	
DIGIT_2: Hex_to_7_Seg
	port map(dig_2, R_bcd6);
	
DIGIT_3: Hex_to_7_Seg
	port map(dig_3, R_bcd5);
	
DIGIT_4: Hex_to_7_Seg
	port map(dig_4, R_bcd4);
	
DIGIT_5: Hex_to_7_Seg
	port map(dig_5, R_bcd3);

DIGIT_6: Hex_to_7_Seg
	port map(dig_6, R_bcd2);

DIGIT_7: Hex_to_7_Seg
	port map(dig_7, R_bcd1);

DIGIT_8: Hex_to_7_Seg
	port map(dig_8, R_bcd0);
	
DIGIT_9: Hex_to_7_Seg
	port map(dig_9, A_bcd1);
	
--DIGIT_10: Hex_to_7_Seg
--	port map(dig_10, A_sign);
	
DIGIT_11: Hex_to_7_Seg
	port map(dig_11, A_bcd2);	
	
DIGIT_12: Hex_to_7_Seg
	port map(dig_12, A_bcd0);	
	
--DIGIT_13: Hex_to_7_Seg
--	port map(dig_13, B_sign);
	
DIGIT_14: Hex_to_7_Seg
	port map(dig_14, B_bcd2);

DIGIT_15: Hex_to_7_Seg
	port map(dig_15, B_bcd1);

DIGIT_16: Hex_to_7_Seg
	port map(dig_16, B_bcd0);		
	
-- 7 Segment Display Controller
SEG_CONTROLLER: Seg_Display_16
	generic map(clock_frequency, segment_refresh)
	port map(ja, dp_b, digit_select, dig_1, dig_2, dig_3, dig_4, dig_5, dig_6, dig_7, dig_8, clk);
	
BASYS_SEG_CONTROLLER: BASYS_7_seg
    generic map(clock_frequency, segment_refresh)
    port map(seg, dp, an, basys_seg_4, basys_seg_3, basys_seg_2, basys_seg_1, in_dp, clk);

	sign_proc : process(clk)
	begin
		if(rising_edge(clk)) then
			if(A_neg = '1') then
				A_sign <= "0111111";
			else
				A_sign <= "1111111";
			end if;
			
			if(B_neg = '1') then
				B_sign <= "0111111";
			else
				B_sign <= "1111111";
			end if;
			
			if(R_neg = '1') then
				Result_sign <= "0111111";
			else
				Result_sign <= "1111111";
			end if;
		end if;
	end process sign_proc;
	
	one_edge_start <= one_lead and (not one_follow);
	ten_edge_start <= ten_lead and (not ten_follow);
	hundred_edge_start <= hundred_lead and (not hundred_follow);
	start_start <= start_lead and (not start_follow);
	
	edge_detect_proc : process(clk)
	begin
		if(rising_edge(clk)) then
			one_lead <= one;
			one_follow <= one_lead;
			ten_lead <= ten;
			ten_follow <= ten_lead;
			hundred_lead <= hundred;
			hundred_follow <= hundred_lead;
			start_lead <= start;
			start_follow <= start_lead;
		end if;
	end process edge_detect_proc;
	
	display_proc : process(clk)
	begin
	   if(rising_edge(clk)) then
	       if(sel = '1') then
	           basys_seg_1 <= dig_12;
	           basys_seg_2 <= dig_9;
	           basys_seg_3 <= dig_11;
	           basys_seg_4 <= dig_10;
	       else
	           basys_seg_1 <= dig_16;
               basys_seg_2 <= dig_15;
               basys_seg_3 <= dig_14;
               basys_seg_4 <= dig_13;
	       end if;
	   end if;
	end process display_proc;
	
	add_sub_proc : process(clk)
	begin
		if(rising_edge(clk)) then
			if(one_edge_start = '1') then
				if(add_sub = '1') then
					if(sel = '1' and A_input < 999) then
						A_input <= A_input + 1;
					elsif(sel = '0' and B_input < 999) then
						B_input <= B_input + 1;
					end if;
					if(sel = '1' and A_input > -999) then
				else
						A_input <= A_input - 1;
					elsif(sel = '0' and B_input > -999) then
						B_input <= B_input - 1;
					end if;
				end if;
			
			elsif(ten_edge_start = '1') then
				if(add_sub = '1') then
					if(sel = '1' and A_input < 989) then
						A_input <= A_input + 10;
					elsif(sel = '0' and B_input < 989) then
						B_input <= B_input + 10;
					end if;
				else
					if(sel = '1' and A_input > -989) then
						A_input <= A_input - 10;
					elsif(sel = '0' and B_input > -989) then
						B_input <= B_input - 10;
					end if;
				end if;
			
			elsif(hundred_edge_start = '1') then
				if(add_sub = '1') then
					if(sel = '1' and A_input < 899) then
						A_input <= A_input + 100;
					elsif(sel = '0' and B_input < 899) then
						B_input <= B_input + 100;
					end if;
				else
					if(sel = '1' and A_input > -899) then
						A_input <= A_input - 100;
					elsif(sel = '0' and B_input > -899) then
						B_input <= B_input - 100;
					end if;
				end if;
			
			end if;
			
		end if;
	end process add_sub_proc;

end behavior;