--------------------------------------------------------------------------------
-- Company: <Name>
--
-- File: MAC_FIR.vhd
-- File history:
--
-- Description		: Implementation of 8/16-Tap using Two MAC  FIR filter using 
--					  Single 18x18 MAC
--
-- Targeted device	: Family	:: SmartFusion2  
-- 					  Die		:: M2S050T
--					  Package	:: 896 FBGA	
--			Author	: PHANIKIRAN T
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;

entity TwoMult_8_tap_FIR is
	generic(N : integer := 16);
port(	clk				: in std_logic;
		reset_n			: in std_logic;
		Xn_in			: in std_logic_vector(17 downto 0);
		Data_Valid		: in std_logic;

		Mac_out			: out std_logic_vector(43 downto 0)	   	   	             	     	     	     	            
         );
end TwoMult_8_tap_FIR;


architecture TwoMult_8_tap_FIR_ARCH of TwoMult_8_tap_FIR is


component multacc is
    -- Port list
    port(
        -- Inputs
        A0        : in  std_logic_vector(17 downto 0);
        A0_ACLR_N : in  std_logic;
        A0_EN     : in  std_logic;
        A0_SCLR_N : in  std_logic;
        B0        : in  std_logic_vector(17 downto 0);
        B0_ACLR_N : in  std_logic;
        B0_EN     : in  std_logic;
        B0_SCLR_N : in  std_logic;
        C         : in  std_logic_vector(43 downto 0);
        CLK       : in  std_logic;
        C_ACLR_N  : in  std_logic;
        C_EN      : in  std_logic;
        C_SCLR_N  : in  std_logic;
        P_ACLR_N  : in  std_logic;
        P_EN      : in  std_logic;
        P_SCLR_N  : in  std_logic;
        -- Outputs
        CDOUT     : out std_logic_vector(43 downto 0);
        P         : out std_logic_vector(43 downto 0)
        );
end component multacc;

component multadder is
    -- Port list
    port(
        -- Inputs
        A0        : in  std_logic_vector(17 downto 0);
        A0_ACLR_N : in  std_logic;
        A0_EN     : in  std_logic;
        A0_SCLR_N : in  std_logic;
        B0        : in  std_logic_vector(17 downto 0);
        B0_ACLR_N : in  std_logic;
        B0_EN     : in  std_logic;
        B0_SCLR_N : in  std_logic;
        CDIN      : in  std_logic_vector(43 downto 0);
        CLK       : in  std_logic;
        P_ACLR_N  : in  std_logic;
        P_EN      : in  std_logic;
        P_SCLR_N  : in  std_logic;
        -- Outputs
        CDOUT     : out std_logic_vector(43 downto 0);
        P         : out std_logic_vector(43 downto 0)
        );
end component multadder;

-- coefficient RAM
component Coef_RAM is
    -- Port list
    port(
        -- Inputs
        A_ADDR : in  std_logic_vector(5 downto 0);
        A_BLK  : in  std_logic;
        B_ADDR : in  std_logic_vector(5 downto 0);
        B_BLK  : in  std_logic;
        CLK    : in  std_logic;
        C_ADDR : in  std_logic_vector(5 downto 0);
        C_BLK  : in  std_logic;
        C_DIN  : in  std_logic_vector(17 downto 0);
        -- Outputs
        A_DOUT : out std_logic_vector(17 downto 0);
        B_DOUT : out std_logic_vector(17 downto 0)
        );
end component Coef_RAM;

component Inp_RAM is
    -- Port list
    port(
        -- Inputs
        A_ADDR : in  std_logic_vector(5 downto 0);
        A_BLK  : in  std_logic;
        B_ADDR : in  std_logic_vector(5 downto 0);
        B_BLK  : in  std_logic;
        CLK    : in  std_logic;
        C_ADDR : in  std_logic_vector(5 downto 0);
        C_BLK  : in  std_logic;
        C_DIN  : in  std_logic_vector(17 downto 0);
        -- Outputs
        A_DOUT : out std_logic_vector(17 downto 0);
        B_DOUT : out std_logic_vector(17 downto 0)
        );
end component Inp_RAM;


 -- Inputs
	
	signal Data_Valid_dly	: std_logic;
	signal Data_Valid_dly0	: std_logic;
	signal Data_Valid_dly1	: std_logic;
	signal Data_Valid_dly2	: std_logic;

	signal Coef_rdaddr		: std_logic_vector(4 downto 0);
	
	signal Coef_rdaddr1		: std_logic_vector(5 downto 0);
	signal Coef_rdaddr2		: std_logic_vector(5 downto 0);

	signal Coef_rddata1		: std_logic_vector(17 downto 0);
	signal Coef_rddata2		: std_logic_vector(17 downto 0);

	signal inp_rdaddr		: std_logic_vector(4 downto 0);

	signal inp_rdaddr1		: std_logic_vector(5 downto 0);
	signal inp_rdaddr2		: std_logic_vector(5 downto 0);

	signal inp_rddata1		: std_logic_vector(17 downto 0);
	signal inp_rddata2		: std_logic_vector(17 downto 0);

	signal inp_wraddr		: std_logic_vector(5 downto 0);
	signal inp_wrdata		: std_logic_vector(17 downto 0);
	signal inp_wrdata_dly	: std_logic_vector(17 downto 0);

	signal inp_rden0 		: std_logic;
	signal inp_rden1 		: std_logic;

	signal Coef_rd0 		: std_logic;
	signal Coef_rd1 		: std_logic;

	signal MulAdd_O			: std_logic_vector(43 downto 0);
	signal CDIN1			: std_logic_vector(43 downto 0);
	signal CDOUT1			: std_logic_vector(43 downto 0);

	signal mac_clr			: std_logic;	
	signal clr				: std_logic;
	signal clrsig			: std_logic;
	signal Yn_out			: std_logic_vector(43 downto 0);


	signal INA				: std_logic_vector(17 downto 0);
	signal INB				: std_logic_vector(17 downto 0);


	signal C_ADDR			: std_logic_vector(5 downto 0);
	signal C_DIN			: std_logic_vector(17 downto 0);

	SIGNAL BADDR_Coef 		: std_logic_vector(5 downto 0);
	SIGNAL BADDR_Inp  		: std_logic_vector(5 downto 0);

begin


	-- storing input samples into memory
	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			inp_wraddr	 <= (OTHERS => '0');
		else
			if(rising_edge(clk))then
				if(Data_Valid_dly = '1')then
					inp_wraddr	<= inp_wraddr + '1';
				end if;
			end if;
		end if;
	end process;

	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			inp_wrdata	 <=(OTHERS => '0');
		else
			if(rising_edge(clk))then
				if(Data_Valid = '1')then
					inp_wrdata	 <= Xn_in;
				end if;
			end if;
		end if;
	end process;

	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			inp_wrdata_dly	 <= (others =>  '0');
		else
			if(rising_edge(clk))then
				inp_wrdata_dly	 <= inp_wrdata;
			end if;
		end if;
	end process;

	process(clk, reset_n)
	begin
		if(reset_n = '0') then
			Data_Valid_dly	 <= '0';
			Data_Valid_dly0	 <= '0';
			Data_Valid_dly1	 <= '0';	
			Data_Valid_dly2	 <= '0';	
		else
			if(rising_edge(clk))then
				Data_Valid_dly	 <= Data_Valid;
				Data_Valid_dly0	 <= Data_Valid_dly;
				Data_Valid_dly1	 <= Data_Valid_dly0;	
				Data_Valid_dly2	 <= Data_Valid_dly1;
			end if;
		end if;
	end process;


 -- Read a coeffcient1(0 to 7)  

	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			Coef_rdaddr	<= (OTHERS => '0');
		else
			if(rising_edge(clk))then
				if(Coef_rdaddr = "111")then
					Coef_rdaddr	<= (OTHERS => '0');
				elsif(Data_Valid_dly0 = '1')then	
					Coef_rdaddr	<= Coef_rdaddr + '1';
				end if;
			end if;
		end if;
	end process;

 -- Read a coeffcient2(8 to 15) 

	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			Coef_rdaddr1	<= (OTHERS => '0');
			Coef_rdaddr2	<= (OTHERS => '0');
		else
			if(rising_edge(clk))then
				Coef_rdaddr1 <= '0' & Coef_rdaddr;
				Coef_rdaddr2 <= '1' & Coef_rdaddr;
			end if;
		end if;
	end process;


	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			inp_rdaddr	<= (others => '0');
		else
			if(rising_edge(clk))then
				if(Data_Valid_dly0 = '1')then
					inp_rdaddr	<= inp_rdaddr  + '1';
				end if;
			end if;
		end if;
	end process;


	process(clk, reset_n)
	begin
		if (reset_n = '0') then
			inp_rdaddr1	<= (OTHERS => '0');
			inp_rdaddr2	<= (OTHERS => '0');
		else
			if(rising_edge(clk))then
				inp_rdaddr1 <= '0' & inp_rdaddr;
				inp_rdaddr2 <= '1' & inp_rdaddr;
			end if;
		end if;
	end process;


	process(clk, reset_n)
	begin
		if(reset_n = '0') then
			clrsig <= '0';
		else
			if(rising_edge(clk))then
				if(Data_Valid_dly2 = '1')then
					clrsig <= '1';
				else
					clrsig <= '0';	
				end if;
			end if;
		end if;
	end process;

	process(clk, reset_n)
	begin
		if(reset_n = '0') then
			clr	 <= '0';
		else
			if(rising_edge(clk))then
				clr	 <= clrsig;
			end if;
		end if;
	end process;

	mac_clr <= not(clr);

	process(clk, reset_n)
	begin
		if(reset_n = '0') then
			Mac_out	 <= (others => '0');
		else
			if(rising_edge(clk))then
				if(clr = '1')then
				  Mac_out <= Yn_out;
				end if;
			end if;
		end if;
	end process;

CDIN1 <= (others => '0');

U0: multadder
	port map(
        -- Inputs
        A0        => inp_rddata1,
        A0_ACLR_N => reset_n,
        A0_EN     => '1',
        A0_SCLR_N => '1',
        B0        => Coef_rddata1,
        B0_ACLR_N => reset_n,
        B0_EN     => '1',
        B0_SCLR_N => '1',
		CDIN      => CDIN1, 
        CLK       => CLK,
        P_ACLR_N  => reset_n,
        P_EN      => '1',
        P_SCLR_N  => '1',
        -- Outputs
        CDOUT     => CDOUT1,
        P         => OPEN
        );

U1: multadder
	port map(
        -- Inputs
        A0        => inp_rddata2,
        A0_ACLR_N => reset_n,
        A0_EN     => '1',
        A0_SCLR_N => '1',
        B0        => Coef_rddata2,
        B0_ACLR_N => reset_n,
        B0_EN     => '1',
        B0_SCLR_N => '1',
		CDIN      => CDOUT1,
        CLK       => CLK,
        P_ACLR_N  => reset_n,
        P_EN      => '1',
        P_SCLR_N  => '1',
        -- Outputs
        CDOUT     => OPEN,
        P         => MulAdd_O
        );

U2: multacc
	port map(
        -- Inputs
        A0        => INA,
        A0_ACLR_N => reset_n,
        A0_EN     => '1',
        A0_SCLR_N => '1',
        B0        => INB,
        B0_ACLR_N => reset_n,
        B0_EN     => '1',
        B0_SCLR_N => '1',
		C         => MulAdd_O,

        C_ACLR_N  => reset_n,
        C_EN      => '1',
        C_SCLR_N  => '1',

        CLK       => CLK,
        P_ACLR_N  => reset_n,
        P_EN      => '1',
        P_SCLR_N  => mac_clr,
        -- Outputs
        CDOUT     => OPEN,
        P         => Yn_out
        );

U3: Coef_RAM 
    -- Port list
    port map(
        -- Inputs
        A_ADDR 			=> Coef_rdaddr1,
		A_BLK			=> Coef_rd0,
        B_ADDR 			=> Coef_rdaddr2,
		B_BLK 			=> Coef_rd1,
        CLK    			=> Clk,
        C_ADDR 			=> C_ADDR,
		C_BLK			=> '0',	
        C_DIN  			=> C_DIN,
        -- Outputs
        A_DOUT 			=> Coef_rddata1,
        B_DOUT 			=> Coef_rddata2
        );

U4: Inp_RAM
    -- Port list
    port map(

        -- Inputs
        A_ADDR 			=> inp_rdaddr1,
		A_BLK			=> inp_rden0,
        B_ADDR 			=> inp_rdaddr2,
		B_BLK 			=> inp_rden1,
		CLK				=> Clk,
        C_ADDR 			=> inp_wraddr,
		C_BLK			=> Data_Valid_dly,	
        C_DIN  			=> inp_wrdata_dly,

        -- Outputs
        A_DOUT 			=> inp_rddata1,
        B_DOUT 			=> inp_rddata2

        );


end TwoMult_8_tap_FIR_ARCH;   




