----------------------------------------------
-- MSS copyright 2003-2007
-- Filename: RAISED_COS2_40CORE.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: RAISED_COS8_25.VHD 1/24/06, RAISED_COS4E.VHD, 3-1-03
-- Edit date: 5/27/07
-- Revision: 1
--
-- One of two parallel filters within the RAISED_COS2_40.VHD
-- component. Goal is to simplify code and void duplication.
-- 
-- Coefficients: 
--coeff(1) = 0
--coeff(2) = 1
--coeff(3) = 0
--coeff(4) = 4 (instead of 5)
--coeff(5) = 0
--coeff(6) = -10 = -8 -2
--coeff(7) = 0;
--coeff(8) = -8
--coeff(9) = 0
--coeff(10) = 88 = 64 + 16 + 8 (instead of 87)
--coeff(11) = 0
--coeff(12) = -304 = -256 - 64 + 16 (instead of -305)
--coeff(13) = 0
--coeff(14) = 1256 = 1024 + 256 - 16 -8;	
--coeff(15) = 2048
-- See Matlab program RAISEDCOS_2_40.m
----------------------------------------------      
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity RAISED_COS2_40CORE is
    port (
		CLK: in std_logic;
			-- reference clock for synchronous design
		 FIL_IN0: in std_logic_vector(13 downto 0);
		 FIL_IN1: in std_logic_vector(13 downto 0);
		 FIL_IN2: in std_logic_vector(13 downto 0);
		 FIL_IN3: in std_logic_vector(13 downto 0);
		 FIL_IN4: in std_logic_vector(13 downto 0);
		 FIL_IN5: in std_logic_vector(13 downto 0);
		 FIL_IN6: in std_logic_vector(13 downto 0);
		 FIL_IN7: in std_logic_vector(13 downto 0);
		 FIL_IN8: in std_logic_vector(13 downto 0);
		 FIL_IN9: in std_logic_vector(13 downto 0);
		 FIL_IN10: in std_logic_vector(13 downto 0);
		 FIL_IN11: in std_logic_vector(13 downto 0);
		 FIL_IN12: in std_logic_vector(13 downto 0);
		 FIL_IN13: in std_logic_vector(13 downto 0);
		 FIL_IN14: in std_logic_vector(13 downto 0);
		 FIL_IN15: in std_logic_vector(13 downto 0);
		 FIL_IN16: in std_logic_vector(13 downto 0);
		 FIL_IN17: in std_logic_vector(13 downto 0);
		 FIL_IN18: in std_logic_vector(13 downto 0);
		 FIL_IN19: in std_logic_vector(13 downto 0);
		 FIL_IN20: in std_logic_vector(13 downto 0);
		 FIL_IN21: in std_logic_vector(13 downto 0);
		 FIL_IN22: in std_logic_vector(13 downto 0);
		 FIL_IN23: in std_logic_vector(13 downto 0);
		 FIL_IN24: in std_logic_vector(13 downto 0);
		 FIL_IN25: in std_logic_vector(13 downto 0);
		 FIL_IN26: in std_logic_vector(13 downto 0);
		 FIL_IN27: in std_logic_vector(13 downto 0);

		DATA_OUT: out std_logic_vector(13 downto 0)
        	-- Input to Output Processing latency 4 CLK periods.
    );
end entity;

architecture RAISED_COS_arch of RAISED_COS2_40CORE is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- suffix _D denotes a one-CLK delayed version of the net with the same name
constant N: integer := 13;   -- precision

-- temporary nets
signal FIL_A1: std_logic_vector(N-11 downto 0);
signal FIL_A2: std_logic_vector(N-11 downto 0);
signal FIL_A: std_logic_vector(N-11 downto 0);
signal FIL_A_D: std_logic_vector(N-11 downto 0);
signal FIL_B1: std_logic_vector(N-9 downto 0);
signal FIL_B2: std_logic_vector(N-9 downto 0);
signal FIL_B: std_logic_vector(N-9 downto 0);
signal FIL_B_D: std_logic_vector(N-9 downto 0);
signal FIL_C1: std_logic_vector(N-8 downto 0);
signal FIL_C2: std_logic_vector(N-8 downto 0);
signal FIL_C: std_logic_vector(N-8 downto 0);
signal FIL_C_D: std_logic_vector(N-8 downto 0);
signal FIL_D1: std_logic_vector(N-8 downto 0);
signal FIL_D2: std_logic_vector(N-8 downto 0);
signal FIL_D: std_logic_vector(N-8 downto 0);
signal FIL_D_D: std_logic_vector(N-8 downto 0);
signal FIL_E1: std_logic_vector(N-5 downto 0);
signal FIL_E2: std_logic_vector(N-5 downto 0);
signal FIL_E: std_logic_vector(N-5 downto 0);
signal FIL_E_D: std_logic_vector(N-5 downto 0);
signal FIL_F1: std_logic_vector(N-3 downto 0);
signal FIL_F2: std_logic_vector(N-3 downto 0);
signal FIL_F: std_logic_vector(N-3 downto 0);
signal FIL_F_D: std_logic_vector(N-3 downto 0);
signal FIL_H1: std_logic_vector(N-1 downto 0);
signal FIL_H2: std_logic_vector(N-1 downto 0);
signal FIL_H: std_logic_vector(N-1 downto 0);
signal FIL_H_D: std_logic_vector(N-1 downto 0);
signal FIL_I1: std_logic_vector(N-6 downto 0);
signal FIL_I2: std_logic_vector(N-6 downto 0);
signal FIL_I: std_logic_vector(N-6 downto 0);
signal FIL_I_D: std_logic_vector(N-6 downto 0);
signal FIL_J1: std_logic_vector(N-7 downto 0);
signal FIL_J2: std_logic_vector(N-7 downto 0);
signal FIL_J: std_logic_vector(N-7 downto 0);
signal FIL_J_D: std_logic_vector(N-7 downto 0);
signal FIL_K1: std_logic_vector(N-2 downto 0);
signal FIL_K2: std_logic_vector(N-2 downto 0);
signal FIL_K: std_logic_vector(N-2 downto 0);
signal FIL_K_D: std_logic_vector(N-2 downto 0);
signal FIL_L1: std_logic_vector(N-6 downto 0);
signal FIL_L2: std_logic_vector(N-6 downto 0);
signal FIL_L: std_logic_vector(N-6 downto 0);
signal FIL_L_D: std_logic_vector(N-6 downto 0);
signal FIL_IN14_D: std_logic_vector(N downto 0);

signal FIL_O1: std_logic_vector(N-8 downto 0);
signal FIL_O2: std_logic_vector(N-8 downto 0);
signal FIL_O: std_logic_vector(N-8 downto 0);
signal FIL_O_D: std_logic_vector(N-8 downto 0);
signal FIL_P1: std_logic_vector(N-7 downto 0);
signal FIL_P2: std_logic_vector(N-7 downto 0);
signal FIL_P: std_logic_vector(N-7 downto 0);
signal FIL_P_D: std_logic_vector(N-7 downto 0);
signal FIL_Q1: std_logic_vector(N-5 downto 0);
signal FIL_Q2: std_logic_vector(N-5 downto 0);
signal FIL_Q: std_logic_vector(N-5 downto 0);
signal FIL_Q_D: std_logic_vector(N-5 downto 0);
signal FIL_R1: std_logic_vector(N-4 downto 0);
signal FIL_R2: std_logic_vector(N-4 downto 0);
signal FIL_R: std_logic_vector(N-4 downto 0);
signal FIL_R_D: std_logic_vector(N-4 downto 0);
signal FIL_S1: std_logic_vector(N-1 downto 0);
signal FIL_S2: std_logic_vector(N-1 downto 0);
signal FIL_S: std_logic_vector(N-1 downto 0);
signal FIL_S_D: std_logic_vector(N-1 downto 0);
signal FIL_T1: std_logic_vector(N+1 downto 0);
signal FIL_T2: std_logic_vector(N+1 downto 0);
signal FIL_T: std_logic_vector(N+1 downto 0);
signal FIL_T_D: std_logic_vector(N+1 downto 0);
signal FIL_U1: std_logic_vector(N-6 downto 0);
signal FIL_U2: std_logic_vector(N-6 downto 0);
signal FIL_U: std_logic_vector(N-6 downto 0);
signal FIL_U_D: std_logic_vector(N-6 downto 0);
signal FIL_V1: std_logic_vector(N-3 downto 0);
signal FIL_V2: std_logic_vector(N-3 downto 0);
signal FIL_V: std_logic_vector(N-3 downto 0);
signal FIL_V_D: std_logic_vector(N-3 downto 0);
signal FIL_W1: std_logic_vector(N+2 downto 0);
signal FIL_W2: std_logic_vector(N+2 downto 0);
signal FIL_W: std_logic_vector(N+2 downto 0);
signal FIL_W_D: std_logic_vector(N+2 downto 0);

signal FIL_CC1: std_logic_vector(N+4 downto 0);
signal FIL_CC2: std_logic_vector(N+4 downto 0);
signal FIL_CC3: std_logic_vector(N+4 downto 0);
signal FIL_CC: std_logic_vector(N+4 downto 0);
signal FIL_CC_D: std_logic_vector(N+4 downto 0);

signal FIL_TT: std_logic_vector(N downto 0);

-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin   

-- FIRST LEVEL OF ADDERS
-- FIL_IN0/FIL_IN28, coeff(1) = 0/4096

-- FIL_IN1/FIL_IN27, coeff(2) = 1/4096 (shifted 12 notches)
FIL_A1(N-12 downto 0) <= FIL_IN1(N downto 12);
FIL_A1(N-11) <= FIL_IN1(N);
FIL_A2(N-12 downto 0) <= FIL_IN27(N downto 12);
FIL_A2(N-11) <= FIL_IN27(N);
FIL_A <= FIL_A1 + FIL_A2;

-- FIL_IN2/FIL_IN26, coeff(3) = 0/4096

-- FIL_IN3/FIL_IN25, coeff(4) = 4/4096 (shifted 10 notches)
FIL_B1(N-10 downto 0) <= FIL_IN3(N downto 10);
FIL_B1(N-9) <= FIL_IN3(N);
FIL_B2(N-10 downto 0) <= FIL_IN25(N downto 10);
FIL_B2(N-9) <= FIL_IN25(N);
FIL_B <= FIL_B1 + FIL_B2;

-- FIL_IN4/FIL_IN24, coeff(5) = 0/4096

-- FIL_IN5/FIL_IN23, coeff(6) = 8/4096 (shifted 9 notches)
FIL_C1(N-9 downto 0) <= FIL_IN5(N downto 9);
FIL_C1(N-8) <= FIL_IN5(N);
FIL_C2(N-9 downto 0) <= FIL_IN23(N downto 9);
FIL_C2(N-8) <= FIL_IN23(N);
FIL_C <= FIL_C1 + FIL_C2;

-- FIL_IN6/FIL_IN22, coeff(7) = 0/4096

-- FIL_IN7/FIL_IN21, coeff(8) = 8/4096 (shifted 9 notches)
FIL_D1(N-9 downto 0) <= FIL_IN7(N downto 9);
FIL_D1(N-8) <= FIL_IN7(N);
FIL_D2(N-9 downto 0) <= FIL_IN21(N downto 9);
FIL_D2(N-8) <= FIL_IN21(N);
FIL_D <= FIL_D1 + FIL_D2;

-- FIL_IN8/FIL_IN20, coeff(9) = 0/4096

-- FIL_IN9/FIL_IN19, coeff(10) = 64/4096 (shifted 6 notches)
FIL_E1(N-6 downto 0) <= FIL_IN9(N downto 6);
FIL_E1(N-5) <= FIL_IN9(N);
FIL_E2(N-6 downto 0) <= FIL_IN19(N downto 6);
FIL_E2(N-5) <= FIL_IN19(N);
FIL_E <= FIL_E1 + FIL_E2;

-- FIL_IN10/FIL_IN18, coeff(11) = 0/4096

-- FIL_IN11/FIL_IN17, coeff(12) = 256/4096 (shifted 4 notches)
FIL_F1(N-4 downto 0) <= FIL_IN11(N downto 4);
FIL_F1(N-3) <= FIL_IN11(N);
FIL_F2(N-4 downto 0) <= FIL_IN17(N downto 4);
FIL_F2(N-3) <= FIL_IN17(N);
FIL_F <= FIL_F1 + FIL_F2;

-- FIL_IN12/FIL_IN16, coeff(13) = 0/4096

-- FIL_IN13/FIL_IN15, coeff(14) = 1024/4096 (shifted 2 notches)
FIL_H1(N-2 downto 0) <= FIL_IN13(N downto 2);
FIL_H1(N-1) <= FIL_IN13(N);
FIL_H2(N-2 downto 0) <= FIL_IN15(N downto 2);
FIL_H2(N-1) <= FIL_IN15(N);
FIL_H <= FIL_H1 + FIL_H2;

-- FIL_E/4 + FIL_F/16 
FIL_I1(N-7 downto 0) <= FIL_E(N-5 downto 2);
FIL_I1(N-6) <= FIL_E(N-5);
FIL_I2(N-7 downto 0) <= FIL_F(N-3 downto 4);
FIL_I2(N-6) <= FIL_F(N-3);
FIL_I <= FIL_I1 + FIL_I2;

-- FIL_E/8 - FIL_H/128 
FIL_J1(N-8 downto 0) <= FIL_E(N-5 downto 3);
FIL_J1(N-7) <= FIL_E(N-5);
FIL_J2(N-8 downto 0) <= FIL_H(N-1 downto 7);
FIL_J2(N-7) <= FIL_H(N-1);
FIL_J <= FIL_J1 - FIL_J2;

-- - FIL_F/4 + FIL_H/4
FIL_K1(N-5 downto 0) <= FIL_F(N-3 downto 2);
FIL_K1(N-2 downto N-4) <= (others => FIL_F(N-3));
FIL_K2(N-3 downto 0) <= FIL_H(N-1 downto 2);
FIL_K2(N-2) <= FIL_H(N-1);
FIL_K <= FIL_K2 - FIL_K1;

-- FIL_C/4 + FIL_H/64 
FIL_L1(N-10 downto 0) <= FIL_C(N-8 downto 2);
FIL_L1(N-6 downto N-9) <= (others => FIL_C(N-8));
FIL_L2(N-7 downto 0) <= FIL_H(N-1 downto 6);
FIL_L2(N-6) <= FIL_H(N-1);
FIL_L <= FIL_L1 + FIL_L2;

-- 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_F_D <= FIL_F;
		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_IN14_D <= FIL_IN14;
	end if;
end process;

-- FIL_A + FIL_B
FIL_O1(N-11 downto 0) <= FIL_A_D;
FIL_O1(N-8 downto N-10) <= (others => FIL_A_D(N-11));
FIL_O2(N-9 downto 0) <= FIL_B_D;
FIL_O2(N-8) <= FIL_B_D(N-9);
FIL_O <= FIL_O1 + FIL_O2;

-- FIL_C + FIL_D
-- do the negative later
FIL_P1(N-8 downto 0) <= FIL_C_D;
FIL_P1(N-7) <= FIL_C_D(N-8);
FIL_P2(N-8 downto 0) <= FIL_D_D;
FIL_P2(N-7) <= FIL_D_D(N-8);
FIL_P <= FIL_P1 + FIL_P2;

-- FIL_J - FIL_L
-- do the negative later
FIL_Q1(N-7 downto 0) <= FIL_J_D;
FIL_Q1(N-5 downto N-6) <= (others => FIL_J_D(N-7));
FIL_Q2(N-6 downto 0) <= FIL_L_D;
FIL_Q2(N-5) <= FIL_L_D(N-6);
FIL_Q <= FIL_Q1 - FIL_Q2;

---FIL_E + FIL_I
FIL_R1(N-5 downto 0) <= FIL_E_D;
FIL_R1(N-4) <= FIL_E_D(N-5);
FIL_R2(N-6 downto 0) <= FIL_I_D;
FIL_R2(N-4 downto N-5) <= (others => FIL_I_D(N-6));
FIL_R <= FIL_R1 + FIL_R2;

-- - FIL_F + FIL_K
-- do the negative later
FIL_S1(N-3 downto 0) <= FIL_F_D;
FIL_S1(N-1 downto N-2) <= (others => FIL_F_D(N-3));
FIL_S2(N-2 downto 0) <= FIL_K_D;
FIL_S2(N-1) <= FIL_K_D(N-2);
FIL_S <= FIL_S2 - FIL_S1;

-- FIL_H + FIL_IN14_D
FIL_T1(N-1 downto 0) <= FIL_H_D;
FIL_T1(N+1 downto N) <= (others => FIL_H_D(N-1));
FIL_T2(N downto 0) <= FIL_IN14_D;
FIL_T2(N+1) <= FIL_IN14_D(N);
FIL_T <= FIL_T1 + FIL_T2;
		
-- FIL_O - FIL_P
FIL_U1(N-8 downto 0) <= FIL_O;
FIL_U1(N-6 downto N-7) <= (others => FIL_O(N-8));
FIL_U2(N-7 downto 0) <= FIL_P;
FIL_U2(N-6) <= FIL_P(N-7);
FIL_U <= FIL_U1 - FIL_U2;
		
-- FIL_Q + FIL_R
FIL_V1(N-5 downto 0) <= FIL_Q;
FIL_V1(N-3 downto N-4) <= (others => FIL_Q(N-5));
FIL_V2(N-4 downto 0) <= FIL_R;
FIL_V2(N-3) <= FIL_R(N-4);
FIL_V <= FIL_V1 + FIL_V2;
		
-- FIL_S + FIL_T
FIL_W1(N-1 downto 0) <= FIL_S;
FIL_W1(N+2 downto N) <= (others => FIL_S(N-1));
FIL_W2(N+1 downto 0) <= FIL_T;
FIL_W2(N+2) <= FIL_T(N+1);
FIL_W <= FIL_W1 + FIL_W2;

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

-- FIL_U + FIL_V + FIL_W
FIL_CC1(N-6 downto 0) <= FIL_U_D;
FIL_CC1(N+4 downto N-5) <= (others => FIL_U_D(N-6));
FIL_CC2(N-3 downto 0) <= FIL_V_D;
FIL_CC2(N+4 downto N-2) <= (others => FIL_V_D(N-3));
FIL_CC3(N+2 downto 0) <= FIL_W_D;
FIL_CC3(N+4 downto N+3) <= (others => FIL_W_D(N+2));
FIL_CC <= FIL_CC1 + FIL_CC2 + FIL_CC3;

-- FOURTH LEVEL OF ADDERS
RECLOCK_003: process(CLK)
begin   
	if rising_edge(CLK) then
		FIL_CC_D <= FIL_CC;
	end if;
end process;

-- 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_CC_D(N+4) = '1') and (FIL_CC_D(N+3 downto N) /= "1111") then	
			-- negative overflow
			FIL_TT(N) <= '1';	-- most negative
			FIL_TT(N-1 downto 1) <= (others => '0');	-- most negative
			FIL_TT(0) <= '1';	-- avoid -2^n case for symmetry.
		elsif(FIL_CC_D(N+4) = '0') and (FIL_CC_D(N+3 downto N) /= "0000") then	
			FIL_TT(N) <= '0';	-- most positive
			FIL_TT(N-1 downto 0) <= (others => '1');	-- most positive
		else	-- within range
			FIL_TT <= FIL_CC_D(N downto 0);
		end if;		
	end if;
end process;
		
DATA_OUT <= FIL_TT;

end RAISED_COS_arch;					