----------------------------------------------
-- MSS copyright 1999-2011
-- Filename: FIRRCOS20.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: similar to most RAISED_COS5x.vhd
-- Edit date: 7/27/11
-- Revision: 2 
--
-- VHDL code for single raised cosine square root FIR. No decimation/no interpolation.
-- 20-taps (low-complexity), but high sidelobes (-32dB).
-- Another LPF should be cascaded when the application requires very low sidelobes.
-- 20% rolloff. Single stream. 
-- Input: 2 samples / symbol
-- Output: 2 samples / symbol
-- Maximum rate: one input sample per CLK.
-- Latency is 5 CLK.
--
-- Rev 2 7/27/11 AZ
-- Simulation initialization
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity FIRRCOS20 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)
			-- signal after raised cosine square root filter.
			-- Read at rising edge of CLK and SAMPLE_CLK_OUT = '1'.
    );
end entity;

architecture Behavioral of firrcos20 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) := (others => '0');
signal FIL_IN2: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN3: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN4: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN5: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN6: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN7: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN8: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN9: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN10: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN11: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN12: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN13: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN14: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN15: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN16: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN17: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN18: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN19: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN20: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_IN21: std_logic_vector(13 downto 0) := (others => '0');

-- intermediate nets
signal FIL_A: std_logic_vector(7 downto 0) := (others => '0');
signal FIL_A1: std_logic_vector(7 downto 0) := (others => '0');
signal FIL_A2: std_logic_vector(7 downto 0) := (others => '0');
signal FIL_B: std_logic_vector(7 downto 0) := (others => '0');
signal FIL_B1: std_logic_vector(7 downto 0) := (others => '0');
signal FIL_B2: std_logic_vector(7 downto 0) := (others => '0');
signal FIL_C: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_C1: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_C2: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_D: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_D1: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_D2: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_E: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_E1: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_E2: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_F: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_F1: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_F2: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_G: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_G1: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_G2: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_H: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_H1: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_H2: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_I: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_I1: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_I2: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_J: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_J_D: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_J1: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_J2: std_logic_vector(12 downto 0) := (others => '0');

signal FIL_K: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_K_D: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_K1: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_K2: std_logic_vector(8 downto 0) := (others => '0');
signal FIL_L: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_L_D: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_L1: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_L2: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_M: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_M_D: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_M1: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_M2: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_N: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_N_D: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_N1: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_N2: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_O: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_O_D: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_O1: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_O2: std_logic_vector(9 downto 0) := (others => '0');
signal FIL_P: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_P_D: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_P1: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_P2: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_Q: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_Q_D: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_Q1: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_Q2: std_logic_vector(13 downto 0) := (others => '0');

signal FIL_R: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_R1: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_R2: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_S: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_S1: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_S2: std_logic_vector(10 downto 0) := (others => '0');
signal FIL_T: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_T_D: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_T1: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_T2: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_T3: std_logic_vector(12 downto 0) := (others => '0');
signal FIL_U: std_logic_vector(14 downto 0) := (others => '0');
signal FIL_U_D: std_logic_vector(14 downto 0) := (others => '0');
signal FIL_U1: std_logic_vector(14 downto 0) := (others => '0');
signal FIL_U2: std_logic_vector(14 downto 0) := (others => '0');
signal FIL_V: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_V_D: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_V1: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_V2: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_W: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_W_D: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_W1: std_logic_vector(11 downto 0) := (others => '0');
signal FIL_W2: std_logic_vector(11 downto 0) := (others => '0');

signal FIL_X: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_X_D: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_X1: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_X2: std_logic_vector(13 downto 0) := (others => '0');
signal FIL_Y: std_logic_vector(15 downto 0) := (others => '0');
signal FIL_Y_D: std_logic_vector(15 downto 0) := (others => '0');
signal FIL_Y1: std_logic_vector(15 downto 0) := (others => '0');
signal FIL_Y2: std_logic_vector(15 downto 0) := (others => '0');

signal FIL_Z: std_logic_vector(16 downto 0) := (others => '0');
signal FIL_Z1: std_logic_vector(16 downto 0) := (others => '0');
signal FIL_Z2: std_logic_vector(16 downto 0) := (others => '0');

signal FIL_AA: std_logic_vector(13 downto 0) := (others => '0');

signal SAMPLE_CLK_IN_D: std_logic := '0';
signal SAMPLE_CLK_IN_D2: std_logic := '0';
signal SAMPLE_CLK_IN_D3: std_logic := '0';
signal SAMPLE_CLK_IN_D4: std_logic := '0';
-----------------------------------------------------------------
-- 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) = 16/2048 (shift by 7 bits) 
FIL_A1 <= FIL_IN1(13) & FIL_IN1(13 downto 7);
FIL_A2 <= FIL_IN21(13) & FIL_IN21(13 downto 7);
FIL_A <= FIL_A1 + FIL_A2;

-- coeff(2) = coeff(20) = 16/2048 (shift by 7 bits) 
FIL_B1 <= FIL_IN2(13) & FIL_IN2(13 downto 7);
FIL_B2 <= FIL_IN20(13) & FIL_IN20(13 downto 7);
FIL_B <= FIL_B1 + FIL_B2;

-- coeff(3) = coeff(19) = 32/2048 (shift by 6 bits) 
FIL_C1 <= FIL_IN3(13) & FIL_IN3(13 downto 6);
FIL_C2 <= FIL_IN19(13) & FIL_IN19(13 downto 6);
FIL_C <= FIL_C1 + FIL_C2;

-- coeff(4) = coeff(18) = 32/2048 (shift by 6 bits) 
FIL_D1 <= FIL_IN4(13) & FIL_IN4(13 downto 6);
FIL_D2 <= FIL_IN18(13) & FIL_IN18(13 downto 6);
FIL_D <= FIL_D1 + FIL_D2;

-- coeff(5) = coeff(17) = 32/2048 (shift by 6 bits) 
FIL_E1 <= FIL_IN5(13) & FIL_IN5(13 downto 6);
FIL_E2 <= FIL_IN17(13) & FIL_IN17(13 downto 6);
FIL_E <= FIL_E1 + FIL_E2;

-- coeff(6) = coeff(16) = 64/2048 (shift by 5 bits) 
FIL_F1 <= FIL_IN6(13) & FIL_IN6(13 downto 5);
FIL_F2 <= FIL_IN16(13) & FIL_IN16(13 downto 5);
FIL_F <= FIL_F1 + FIL_F2;

-- coeff(7) = coeff(15) = 32/2048 (shift by 6 bits) 
FIL_G1 <= FIL_IN7(13) & FIL_IN7(13 downto 6);
FIL_G2 <= FIL_IN15(13) & FIL_IN15(13 downto 6);
FIL_G <= FIL_G1 + FIL_G2;

-- coeff(8) = coeff(14) = 128/2048 (shift by 4 bits) 
FIL_H1 <= FIL_IN8(13) & FIL_IN8(13 downto 4);
FIL_H2 <= FIL_IN14(13) & FIL_IN14(13 downto 4);
FIL_H <= FIL_H1 + FIL_H2;

-- coeff(9) = coeff(13) = 32/2048 (shift by 6 bits) 
FIL_I1 <= FIL_IN9(13) & FIL_IN9(13 downto 6);
FIL_I2 <= FIL_IN13(13) & FIL_IN13(13 downto 6);
FIL_I <= FIL_I1 + FIL_I2;

-- coeff(10) = coeff(12) = 512/2048 (shift by 2 bits) 
FIL_J1 <= FIL_IN10(13) & FIL_IN10(13 downto 2);
FIL_J2 <= FIL_IN12(13) & FIL_IN12(13 downto 2);
FIL_J <= FIL_J1 + FIL_J2;

-- SECOND LEVEL OF ADDERS
-- FIL_B - FIL_A
FIL_K1 <= FIL_B(7) & FIL_B(7 downto 0);
FIL_K2 <= FIL_A(7) & FIL_A(7 downto 0);
FIL_K <= FIL_K1 - FIL_K2;

-- FIL_D + FIL_E
FIL_L1 <= FIL_D(8) & FIL_D(8 downto 0);
FIL_L2 <= FIL_E(8) & FIL_E(8 downto 0);
FIL_L <= FIL_L1 + FIL_L2;

-- FIL_G - FIL_I
FIL_M1 <= FIL_G(8) & FIL_G(8 downto 0);
FIL_M2 <= FIL_I(8) & FIL_I(8 downto 0);
FIL_M <= FIL_M1 - FIL_M2;

-- FIL_F + FIL_F/4
FIL_N1 <= FIL_F(9) & FIL_F(9 downto 0);
FIL_N2(7 downto 0) <= FIL_F(9 downto 2);
FIL_N2(10 downto 8) <= (others => FIL_F(9));
FIL_N <= FIL_N1 + FIL_N2;

-- FIL_C + FIL_F/8
FIL_O1 <= FIL_C(8) & FIL_C(8 downto 0);
FIL_O2(6 downto 0) <= FIL_F(9 downto 3);
FIL_O2(9 downto 7) <= (others => FIL_F(9));
FIL_O <= FIL_O1 + FIL_O2;

-- FIL_H + FIL_H/2
FIL_P1 <= FIL_H(10) & FIL_H(10 downto 0);
FIL_P2(9 downto 0) <= FIL_H(10 downto 1);
FIL_P2(11 downto 10) <= (others => FIL_H(10));
FIL_P <= FIL_P1 + FIL_P2;

-- FIL_IN11/2 + FIL_IN11/32
FIL_Q1 <= FIL_IN11(13) & FIL_IN11(13 downto 1);
FIL_Q2(8 downto 0) <= FIL_IN11(13 downto 5);
FIL_Q2(13 downto 9) <= (others => FIL_IN11(13));
FIL_Q <= FIL_Q1 + FIL_Q2;


-- THIRD LEVEL OF ADDERS  
RECLOCK_001: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_J_D <= FIL_J;
		FIL_K_D <= FIL_K;
		FIL_L_D <= FIL_L;
		FIL_M_D <= FIL_M;
		FIL_N_D <= FIL_N;
		FIL_O_D <= FIL_O;
		FIL_P_D <= FIL_P;
		FIL_Q_D <= FIL_Q;
	end if;
end process;

-- FIL_K + FIL_O
FIL_R1 <= FIL_O_D(9) & FIL_O_D(9 downto 0);
FIL_R2(8 downto 0) <= FIL_K_D(8 downto 0);
FIL_R2(10 downto 9) <= (others => FIL_K_D(8));
FIL_R <= FIL_R1 + FIL_R2;

-- FIL_L + FIL_L/4
FIL_S1 <= FIL_L_D(9) & FIL_L_D(9 downto 0);
FIL_S2(7 downto 0) <= FIL_L_D(9 downto 2);
FIL_S2(10 downto 8) <= (others => FIL_L_D(9));
FIL_S <= FIL_S1 + FIL_S2;

-- FIL_N + FIL_M + FIL_M/2
FIL_T1(10 downto 0) <=  FIL_N_D(10 downto 0);
FIL_T1(12 downto 11) <= (others => FIL_N_D(10));
FIL_T2(9 downto 0) <= FIL_M_D(9 downto 0);
FIL_T2(12 downto 10) <= (others => FIL_M_D(9));
FIL_T3(8 downto 0) <= FIL_M_D(9 downto 1);
FIL_T3(12 downto 9) <= (others => FIL_M_D(9));
FIL_T <= FIL_T1 + FIL_T2 + FIL_T3;

-- FIL_Q - FIL_P
FIL_U1 <= FIL_Q_D(13) & FIL_Q_D(13 downto 0);
FIL_U2(11 downto 0) <= FIL_P_D(11 downto 0);
FIL_U2(14 downto 12) <= (others => FIL_P_D(11));
FIL_U <= FIL_U1 - FIL_U2;

-- FIL_J + FIL_J/4
FIL_V1 <= FIL_J_D(12) & FIL_J_D(12 downto 0);
FIL_V2(10 downto 0) <= FIL_J_D(12 downto 2);
FIL_V2(13 downto 11) <= (others => FIL_J_D(12));
FIL_V <= FIL_V1 + FIL_V2;

-- FIL_R - FIL_S
FIL_W1 <= FIL_R(10) & FIL_R(10 downto 0);
FIL_W2(10 downto 0) <= FIL_S(10 downto 0);
FIL_W2(11 downto 11) <= (others => FIL_S(10));
FIL_W <= FIL_W1 - FIL_W2;

-- FOURTH LEVEL OF ADDERS  
RECLOCK_002: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_T_D <= FIL_T;
		FIL_U_D <= FIL_U;
		FIL_V_D <= FIL_V;
		FIL_W_D <= FIL_W;
	end if;
end process;

-- FIL_T + FIL_W
FIL_X1 <= FIL_T_D(12) & FIL_T_D(12 downto 0);
FIL_X2(11 downto 0) <= FIL_W_D(11 downto 0);
FIL_X2(13 downto 12) <= (others => FIL_W_D(11));
FIL_X <= FIL_X1 + FIL_X2;

-- FIL_U + FIL_V
FIL_Y1 <= FIL_U_D(14) & FIL_U_D(14 downto 0);
FIL_Y2(13 downto 0) <= FIL_V_D(13 downto 0);
FIL_Y2(15 downto 14) <= (others => FIL_V_D(13));
FIL_Y <= FIL_Y1 + FIL_Y2;

RECLOCK_003: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_X_D <= FIL_X;
		FIL_Y_D <= FIL_Y;
	end if;
end process;

-- FIL_X + FIL_Y
FIL_Z1 <= FIL_Y_D(15) & FIL_Y_D(15 downto 0);
FIL_Z2(13 downto 0) <= FIL_X_D(13 downto 0);
FIL_Z2(16 downto 14) <= (others => FIL_X_D(13));
FIL_Z <= FIL_Z1 + FIL_Z2;


-- 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_Z(16) = '1') and (FIL_Z(15 downto 13) /= "111") then	-- overflow negative
			FIL_AA <= "10000000000001";	-- most negative
		elsif(FIL_Z(16) = '0') and (FIL_Z(15 downto 13) /= "000") then	-- overflow positive
			FIL_AA <= "01111111111111";	-- most positive
		else	-- within range
			FIL_AA <= FIL_Z(13 downto 0);
		end if;		
	end if;
end process;
		
DATA_OUT <= FIL_AA;

RECLOCK_004: 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_OUT <= SAMPLE_CLK_IN_D4;
	end if;
end process;



end Behavioral;

