----------------------------------------------
-- MSS copyright 1999-2013
-- Filename: FIRHALFBAND3.VHD
-- Author: Alain Zarembowitch / MSS
-- Edit date: 4/19/13
-- Revision: 1 
--
-- VHDL code for single half-band FIR. 
-- 20-taps, nearly half of them are zero. 60 dB rejection. 
-- Maximum rate: one input sample per CLK.
-- Latency is 6 CLK.   
-- Higher precision is used during partial sums computation. See also the smaller/lower precision filter.
--
-- Rev 2 4/19/13 AZ
-- One more pipelining stage for better timing
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity FIRHALFBAND3 is
    port (
		CLK: in std_logic;
			-- reference clock for synchronous design
        	-- Input to Output Processing latency 5 CLK periods.
		SAMPLE_CLK_IN: in std_logic;
			-- read input sample at rising_edge of CLK and SAMPLE_CLK_IN  = '1'.
			-- One CLK wide pulse.
		DATA_IN: in std_logic_vector(13 downto 0);
			-- input signal
			-- read at rising edge of CLK when SAMPLE_CLK_IN = '1'

		SAMPLE_CLK_OUT: out std_logic;
		DATA_OUT: out std_logic_vector(13 downto 0)
			-- filtered signal.
			-- Read at rising edge of CLK and SAMPLE_CLK_OUT = '1'.
    );
end entity;

architecture Behavioral of FIRHALFBAND3 is
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- suffix _D denotes a one-CLK delayed version of the net with the same name
-- Filter input
signal FIL_IN1: std_logic_vector(13 downto 0);
signal FIL_IN2: std_logic_vector(13 downto 0);
signal FIL_IN3: std_logic_vector(13 downto 0);
signal FIL_IN4: std_logic_vector(13 downto 0);
signal FIL_IN5: std_logic_vector(13 downto 0);
signal FIL_IN6: std_logic_vector(13 downto 0);
signal FIL_IN7: std_logic_vector(13 downto 0);
signal FIL_IN8: std_logic_vector(13 downto 0);
signal FIL_IN9: std_logic_vector(13 downto 0);
signal FIL_IN10: std_logic_vector(13 downto 0);
signal FIL_IN11: std_logic_vector(13 downto 0);
signal FIL_IN11_D: std_logic_vector(13 downto 0);
signal FIL_IN11_D2: std_logic_vector(13 downto 0);
signal FIL_IN12: std_logic_vector(13 downto 0);
signal FIL_IN13: std_logic_vector(13 downto 0);
signal FIL_IN14: std_logic_vector(13 downto 0);
signal FIL_IN15: std_logic_vector(13 downto 0);
signal FIL_IN16: std_logic_vector(13 downto 0);
signal FIL_IN17: std_logic_vector(13 downto 0);
signal FIL_IN18: std_logic_vector(13 downto 0);
signal FIL_IN19: std_logic_vector(13 downto 0);
signal FIL_IN20: std_logic_vector(13 downto 0);
signal FIL_IN21: std_logic_vector(13 downto 0);

-- intermediate nets
signal FIL_A: std_logic_vector(9 downto 0);
signal FIL_A_D: std_logic_vector(9 downto 0);
signal FIL_A1: std_logic_vector(9 downto 0);
signal FIL_A2: std_logic_vector(9 downto 0);
signal FIL_B: std_logic_vector(11 downto 0);
signal FIL_B_D: std_logic_vector(11 downto 0);
signal FIL_B1: std_logic_vector(11 downto 0);
signal FIL_B2: std_logic_vector(11 downto 0);
signal FIL_C: std_logic_vector(12 downto 0);
signal FIL_C_D: std_logic_vector(12 downto 0);
signal FIL_C1: std_logic_vector(12 downto 0);
signal FIL_C2: std_logic_vector(12 downto 0);
signal FIL_D: std_logic_vector(13 downto 0);
signal FIL_D_D: std_logic_vector(13 downto 0);
signal FIL_D1: std_logic_vector(13 downto 0);
signal FIL_D2: std_logic_vector(13 downto 0);
signal FIL_E: std_logic_vector(15 downto 0);
signal FIL_E_D: std_logic_vector(15 downto 0);
signal FIL_E_D2: std_logic_vector(15 downto 0);
signal FIL_E1: std_logic_vector(15 downto 0);
signal FIL_E2: std_logic_vector(15 downto 0);

signal FIL_F: std_logic_vector(10 downto 0);
signal FIL_F_D: std_logic_vector(10 downto 0);
signal FIL_F1: std_logic_vector(10 downto 0);
signal FIL_F2: std_logic_vector(10 downto 0);
signal FIL_G: std_logic_vector(13 downto 0);
signal FIL_G_D: std_logic_vector(13 downto 0);
signal FIL_G1: std_logic_vector(13 downto 0);
signal FIL_G2: std_logic_vector(13 downto 0);
signal FIL_H: std_logic_vector(7 downto 0);
signal FIL_H_D: std_logic_vector(7 downto 0);
signal FIL_H1: std_logic_vector(7 downto 0);
signal FIL_H2: std_logic_vector(7 downto 0);
signal FIL_I: std_logic_vector(10 downto 0);
signal FIL_I_D: std_logic_vector(10 downto 0);
signal FIL_I1: std_logic_vector(10 downto 0);
signal FIL_I2: std_logic_vector(10 downto 0);
signal FIL_J: std_logic_vector(14 downto 0);
signal FIL_J_D: std_logic_vector(14 downto 0);
signal FIL_J1: std_logic_vector(14 downto 0);
signal FIL_J2: std_logic_vector(14 downto 0);
signal FIL_K: std_logic_vector(12 downto 0);
signal FIL_K_D: std_logic_vector(12 downto 0);
signal FIL_K1: std_logic_vector(12 downto 0);
signal FIL_K2: std_logic_vector(12 downto 0);
signal FIL_L: std_logic_vector(6 downto 0);
signal FIL_L_D: std_logic_vector(6 downto 0);
signal FIL_L1: std_logic_vector(6 downto 0);
signal FIL_L2: std_logic_vector(6 downto 0);
signal FIL_M: std_logic_vector(8 downto 0);
signal FIL_M_D: std_logic_vector(8 downto 0);
signal FIL_M1: std_logic_vector(8 downto 0);
signal FIL_M2: std_logic_vector(8 downto 0);

signal FIL_N: std_logic_vector(11 downto 0);
signal FIL_N1: std_logic_vector(11 downto 0);
signal FIL_N2: std_logic_vector(11 downto 0);
signal FIL_O: std_logic_vector(8 downto 0);
signal FIL_O1: std_logic_vector(8 downto 0);
signal FIL_O2: std_logic_vector(8 downto 0);
signal FIL_P: std_logic_vector(15 downto 0);
signal FIL_P_D: std_logic_vector(15 downto 0);
signal FIL_P1: std_logic_vector(15 downto 0);
signal FIL_P2: std_logic_vector(15 downto 0);
signal FIL_Q: std_logic_vector(13 downto 0);
signal FIL_Q_D: std_logic_vector(13 downto 0);
signal FIL_Q1: std_logic_vector(13 downto 0);
signal FIL_Q2: std_logic_vector(13 downto 0);
signal FIL_R: std_logic_vector(16 downto 0);
signal FIL_R_D: std_logic_vector(16 downto 0);
signal FIL_R1: std_logic_vector(16 downto 0);
signal FIL_R2: std_logic_vector(16 downto 0);
signal FIL_S: std_logic_vector(12 downto 0);
signal FIL_S_D: std_logic_vector(12 downto 0);
signal FIL_S1: std_logic_vector(12 downto 0);
signal FIL_S2: std_logic_vector(12 downto 0);

signal FIL_T: std_logic_vector(14 downto 0);
signal FIL_T_D: std_logic_vector(14 downto 0);
signal FIL_T1: std_logic_vector(14 downto 0);
signal FIL_T2: std_logic_vector(14 downto 0);
signal FIL_U: std_logic_vector(17 downto 0);
signal FIL_U_D: std_logic_vector(17 downto 0);
signal FIL_U1: std_logic_vector(17 downto 0);
signal FIL_U2: std_logic_vector(17 downto 0);

signal FIL_V: std_logic_vector(18 downto 0);
signal FIL_V_D: std_logic_vector(18 downto 0);
signal FIL_V1: std_logic_vector(18 downto 0);
signal FIL_V2: std_logic_vector(18 downto 0);

signal FIL_AA: std_logic_vector(13 downto 0);

signal SAMPLE_CLK_IN_D: std_logic;
signal SAMPLE_CLK_IN_D2: std_logic;
signal SAMPLE_CLK_IN_D3: std_logic;
signal SAMPLE_CLK_IN_D4: std_logic;
signal SAMPLE_CLK_IN_D5: std_logic;
-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin

SHIFT_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') then		
			FIL_IN1 <= DATA_IN;                                                
			FIL_IN2 <= FIL_IN1;                                                
			FIL_IN3 <= FIL_IN2;                                                
			FIL_IN4 <= FIL_IN3;                                                
			FIL_IN5 <= FIL_IN4;                                                
			FIL_IN6 <= FIL_IN5;                                                
			FIL_IN7 <= FIL_IN6;                                                
			FIL_IN8 <= FIL_IN7;                                                
			FIL_IN9 <= FIL_IN8;                                                
			FIL_IN10 <= FIL_IN9;                                                
			FIL_IN11 <= FIL_IN10;                                                
			FIL_IN12 <= FIL_IN11;                                                
			FIL_IN13 <= FIL_IN12;                                                
			FIL_IN14 <= FIL_IN13;                                                
			FIL_IN15 <= FIL_IN14;                                                
			FIL_IN16 <= FIL_IN15;
			FIL_IN17 <= FIL_IN16;                                                
			FIL_IN18 <= FIL_IN17;                                                
			FIL_IN19 <= FIL_IN18;                                                
			FIL_IN20 <= FIL_IN19;                                                
			FIL_IN21 <= FIL_IN20;                                                
		end if;
	end if;
end process;

-- FIRST LEVEL OF ADDERS (fold)
-- coeff(1) = coeff(21) = 0 
-- coeff(2) = coeff(20) = 16/4096 (shift by 8 bits) 
FIL_A1 <= FIL_IN2(13) & FIL_IN2(13 downto 5);
FIL_A2 <= FIL_IN20(13) & FIL_IN20(13 downto 5);
FIL_A <= FIL_A1 + FIL_A2;

-- coeff(3) = coeff(19) = 0 
-- coeff(4) = coeff(18) = 64/4096 (shift by 6 bits) 
FIL_B1 <= FIL_IN4(13) & FIL_IN4(13 downto 3);
FIL_B2 <= FIL_IN18(13) & FIL_IN18(13 downto 3);
FIL_B <= FIL_B1 + FIL_B2;

-- coeff(5) = coeff(17) = 0 
-- coeff(6) = coeff(16) = 128/4096 (shift by 5 bits) 
FIL_C1 <= FIL_IN6(13) & FIL_IN6(13 downto 2);
FIL_C2 <= FIL_IN16(13) & FIL_IN16(13 downto 2);
FIL_C <= FIL_C1 + FIL_C2;

-- coeff(7) = coeff(15) = 0 
-- coeff(8) = coeff(14) = 256/4096 (shift by 4 bits) 
FIL_D1 <= FIL_IN8(13) & FIL_IN8(13 downto 1);
FIL_D2 <= FIL_IN14(13) & FIL_IN14(13 downto 1);
FIL_D <= FIL_D1 + FIL_D2;

-- coeff(9) = coeff(13) = 0 
-- coeff(10) = coeff(12) = 1024/4096 (shift by 2 bits) 
FIL_E1 <= FIL_IN10(13) & FIL_IN10(13 downto 0) & "0";
FIL_E2 <= FIL_IN12(13) & FIL_IN12(13 downto 0) & "0";
FIL_E <= FIL_E1 + FIL_E2;

-- SECOND LEVEL OF ADDERS
RECLOCK_001: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_A_D <= FIL_A;
		FIL_B_D <= FIL_B;
		FIL_C_D <= FIL_C;
		FIL_D_D <= FIL_D;
		FIL_E_D <= FIL_E;
		FIL_IN11_D <= FIL_IN11;
	end if;
end process;

-- FIL_A - FIL_A/8
FIL_F1 <= FIL_A_D(9) & FIL_A_D(9 downto 0);
FIL_F2(6 downto 0) <= FIL_A_D(9 downto 3);
FIL_F2(10 downto 7) <= (others => FIL_A_D(9));
FIL_F <= FIL_F1 - FIL_F2;

-- - FIL_B + FIL_C
FIL_G1 <= FIL_C_D(12) & FIL_C_D(12 downto 0);
FIL_G2(11 downto 0) <= FIL_B_D(11 downto 0);
FIL_G2(13 downto 12) <= (others => FIL_B_D(11));
FIL_G <= FIL_G1 - FIL_G2;

-- FIL_B/32 + FIL_B/64
FIL_H1 <= FIL_B_D(11) & FIL_B_D(11 downto 5);
FIL_H2(5 downto 0) <= FIL_B_D(11 downto 6);
FIL_H2(7 downto 6) <= (others => FIL_B_D(11));
FIL_H <= FIL_H1 + FIL_H2; 

-- FIL_C/8 + FIL_B/8
FIL_I1 <= FIL_C_D(12) & FIL_C_D(12 downto 3);
FIL_I2(8 downto 0) <= FIL_B_D(11 downto 3);
FIL_I2(10 downto 9) <= (others => FIL_B_D(11));
FIL_I <= FIL_I1 + FIL_I2;

-- - FIL_D + FIL_E/4
FIL_J1 <= FIL_D_D(13) & FIL_D_D(13 downto 0);
FIL_J2(13 downto 0) <= FIL_E_D(15 downto 2);
FIL_J2(14 downto 14) <= (others => FIL_E_D(15));
FIL_J <= FIL_J2 - FIL_J1;

-- FIL_D/4 + FIL_D/8
FIL_K1 <= FIL_D_D(13) & FIL_D_D(13 downto 2);
FIL_K2(10 downto 0) <= FIL_D_D(13 downto 3);
FIL_K2(12 downto 11) <= (others => FIL_D_D(13));
FIL_K <= FIL_K2 + FIL_K1;

-- FIL_D/256 + FIL_C/128
FIL_L1 <= FIL_D_D(13) & FIL_D_D(13 downto 8);
FIL_L2(5 downto 0) <= FIL_C_D(12 downto 7);
FIL_L2(6 downto 6) <= (others => FIL_C_D(12));
FIL_L <= FIL_L1 + FIL_L2;

-- FIL_E/256 + FIL_E/512
FIL_M1 <= FIL_E_D(15) & FIL_E_D(15 downto 8);
FIL_M2(6 downto 0) <= FIL_E_D(15 downto 9);
FIL_M2(8 downto 7) <= (others => FIL_E_D(15));
FIL_M <= FIL_M1 + FIL_M2;


-- THIRD LEVEL OF ADDERS  
RECLOCK_002: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_F_D <= FIL_F;
		FIL_G_D <= FIL_G;
		FIL_H_D <= FIL_H;
		FIL_I_D <= FIL_I;
		FIL_J_D <= FIL_J;
		FIL_K_D <= FIL_K;
		FIL_L_D <= FIL_L;
		FIL_M_D <= FIL_M;
		FIL_E_D2 <= FIL_E_D;
		FIL_IN11_D2 <= FIL_IN11_D;
	end if;
end process;

-- FIL_I + FIL_F
FIL_N1 <= FIL_I_D(10) & FIL_I_D(10 downto 0);
FIL_N2(10 downto 0) <= FIL_F_D(10 downto 0);
FIL_N2(11 downto 11) <= (others => FIL_F_D(10));
FIL_N <= FIL_N1 + FIL_N2;

-- - FIL_L + FIL_H
FIL_O1 <= FIL_H_D(7) & FIL_H_D(7 downto 0);
FIL_O2(6 downto 0) <= FIL_L_D(6 downto 0);
FIL_O2(8 downto 7) <= (others => FIL_L_D(6));
FIL_O <= FIL_O1 - FIL_O2;

-- FIL_J + FIL_G 
FIL_P1 <= FIL_J_D(14) & FIL_J_D(14 downto 0);
FIL_P2(13 downto 0) <= FIL_G_D(13 downto 0);
FIL_P2(15 downto 14) <= (others => FIL_G_D(13));
FIL_P <= FIL_P1 + FIL_P2;

-- FIL_K + FIL_M
FIL_Q1 <= FIL_K_D(12) & FIL_K_D(12 downto 0);
FIL_Q2(8 downto 0) <= FIL_M_D(8 downto 0);
FIL_Q2(13 downto 9) <= (others => FIL_M_D(8));
FIL_Q <= FIL_Q1 + FIL_Q2;

-- FIL_E + FIL_IN11/2
FIL_R1 <= FIL_E_D2(15) & FIL_E_D2(15 downto 0);
FIL_R2(15 downto 0) <= FIL_IN11_D2(13 downto 0) & "00";
FIL_R2(16 downto 16) <= (others => FIL_IN11_D2(13));
FIL_R <= FIL_R1 + FIL_R2;

-- FIL_N + FIL_O
FIL_S1 <= FIL_N(11) & FIL_N(11 downto 0);
FIL_S2(8 downto 0) <= FIL_O(8 downto 0);
FIL_S2(12 downto 9) <= (others => FIL_O(8));
FIL_S <= FIL_S1 + FIL_S2;

-- FOURTH LEVEL OF ADDERS  
RECLOCK_003: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_P_D <= FIL_P;
		FIL_Q_D <= FIL_Q;
		FIL_R_D <= FIL_R;
		FIL_S_D <= FIL_S;
	end if;
end process;

-- FIL_S - FIL_Q
FIL_T1 <= FIL_Q_D(13) & FIL_Q_D(13 downto 0);
FIL_T2(12 downto 0) <= FIL_S_D(12 downto 0);
FIL_T2(14 downto 13) <= (others => FIL_S_D(12));
FIL_T <= FIL_T2 - FIL_T1;

-- FIL_P + FIL_R
FIL_U1 <= FIL_R_D(16) & FIL_R_D(16 downto 0);
FIL_U2(15 downto 0) <= FIL_P_D(15 downto 0);
FIL_U2(17 downto 16) <= (others => FIL_P_D(15));
FIL_U <= FIL_U1 + FIL_U2;

RECLOCK_004: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_T_D <= FIL_T;
		FIL_U_D <= FIL_U;
	end if;
end process;

-- FIL_T + FIL_U
FIL_V1 <= FIL_U_D(17) & FIL_U_D(17 downto 0);
FIL_V2(14 downto 0) <= FIL_T_D(14 downto 0);
FIL_V2(18 downto 15) <= (others => FIL_T_D(14));
FIL_V <= FIL_V1 + FIL_V2;


-- clip output to 13 bits (same number of bits as input)  
-- Should be OK since the filter has a maximum gain of 1.
CLIP001: process(CLK)
begin                         
	if rising_edge(CLK) then
		if(FIL_V(18) = '1') and (FIL_V(17 downto 16) /= "11") then	-- overflow negative
			FIL_AA <= "10000000000001";	-- most negative
		elsif(FIL_V(18) = '0') and (FIL_V(17 downto 16) /= "00") then	-- overflow positive
			FIL_AA <= "01111111111111";	-- most positive
		else	-- within range
			FIL_AA <= FIL_V(16 downto 3);
		end if;		
	end if;
end process;
		
DATA_OUT <= FIL_AA;

RECLOCK_005: process(CLK)
begin
	-- Generate the output sample clock
	if rising_edge(CLK) then
		SAMPLE_CLK_IN_D <= SAMPLE_CLK_IN;
		SAMPLE_CLK_IN_D2 <= SAMPLE_CLK_IN_D;
		SAMPLE_CLK_IN_D3 <= SAMPLE_CLK_IN_D2;
		SAMPLE_CLK_IN_D4 <= SAMPLE_CLK_IN_D3;
		SAMPLE_CLK_IN_D5 <= SAMPLE_CLK_IN_D4;
		SAMPLE_CLK_OUT <= SAMPLE_CLK_IN_D5;
	end if;
end process;



end Behavioral;

