----------------------------------------------
-- MSS copyright 1999-2014
-- Filename: FFT_RADIX2_4.VHD
-- Authors: 
-- 	Mike Yoha / MSS
-- 	Alain Zarembowitch / MSS
-- Inheritance: Sirius Satellite Radio receiver FFT_REF.VHD/ 4-19-01
-- Edit date: 4/21/14
-- Revision: 2
--
-- Description: FFT radix 2 or radix 4 butterfly. 
-- changes in Rev 0.002 my
--
--	Rev 0.003 az
-- Removed references to work.math and inc_slv
-- Removed references to fcadd16_2
--
--	Rev 0.004 az
-- Simplified interface. Use SAMPLE_CLK instead of CLK_PHASE
--
--	Rev 0.005 az
-- Corrected timing errors. Latency is now 11 CLKs.
-- Corrected x2 scaling error between XA/YA and XBCD/YBCD coefficients. Normalized.
--
--
--	Rev 0.006 az
-- Adjusted scaling factor to keep maximum range.
-- removed unnecessary clamping on ABCD1 and ABCD2 sums.       
--
-- Rev 0.007 az
-- corrected bug in radix2 and radix4 adder-only path (relative to +/* path)
-- Previously, the COFDM spectrum at the FFT output was not balanced between positive and neg frequencies.
--
-- Rev 0.008 az
-- Added overflow detection flag
--
-- Rev 1 11-21-05 AZ
-- Update code for Spartan-3
--   Remove async_reset (natural FPGA state)
--   Use hardware multipliers
--   Extend precision to 12 bits on both coefficients and samples.
--   reduce latency from 11 CLKs to 6 CLKs
--
-- Rev 2 4/21/14 AZ
-- Extended precision from 12 to 18 bit.
-- Initialize signals for simulation.
-- 
-- Implementation: 
-- Minimum period: 5.146ns (Maximum Frequency: 194.345MHz) Spartan-6 -3
-- Number of Slice Registers 939
-- Number of Slice LUTs 1078
-- Number of BUFG/BUFGCTRLs 1
-- Number of DSP48A1s 6
----------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity FFT_RADIX2_4 is
	port (  
		--// CLOCK, RESET
		CLK: in std_logic;
			-- synchronous reference clock
		SAMPLE_CLK_IN: in std_logic;
			-- start FFT computation (2 cycles) when SAMPLE_CLK_IN = '1'
			-- one CLK wide pulse
			-- KEY ASSUMPTION: SUCCESSIVE SAMPLE PULSES SEPARATED BY AT LEAST
			-- 2 CLKS!

		--// INPUTS 
		-- X is real, Y imaginary
		-- For radix 2, the module performs two butterfiles over 2 CLK phases:
		-- 	1st Radix2 butterfly inputs (X1A + jY1A) and (X1B + jY1B)
		-- 	2nd Radix2 butterfly inputs (X1C + jY1C) and (X1D + jY1D)
		-- KEY ASSUMPTION: THE INPUT SAMPLES X,Y MUST BE FROZEN FOR 2 CLKS
		-- STARTING AT SAMPLE_CLK_IN. 
		X1A: in std_logic_vector(17 downto 0);
		X1B: in std_logic_vector(17 downto 0);
		X1C: in std_logic_vector(17 downto 0);
		X1D: in std_logic_vector(17 downto 0);
		Y1A: in std_logic_vector(17 downto 0);
		Y1B: in std_logic_vector(17 downto 0);
		Y1C: in std_logic_vector(17 downto 0);
		Y1D: in std_logic_vector(17 downto 0);  
		-- Coefficients  Wk = e(j2pik/N) = Cosine + j Sine)
		--	Radix2: 
		--	coefficients are CB/SB for the first butterfly
		--	coefficients are CD/SD for the second butterfly
		-- The coefficients are read at SAMPLE_CLK_IN and stored locally.
		-- Format: 1.17
     	CB: in std_logic_vector(17 downto 0);
     	CC: in std_logic_vector(17 downto 0);
     	CD: in std_logic_vector(17 downto 0);
     	SB: in std_logic_vector(17 downto 0);
     	SC: in std_logic_vector(17 downto 0);
     	SD: in std_logic_vector(17 downto 0);

		OUTPUT_SHIFT: in std_logic_vector(1 downto 0);
			-- shift output 0,1,2 or 3 bits to the left.
			-- when using 0, no overflow can occur.
			-- check OVERFLOW bit to select the OUTPUT_SHIFT.
	

		--// OUTPUTS (4 elements if radix 4, 2 elements used if radix 2)   
		-- Read at rising edge of CLK and SAMPLE_CLK_OUT = '1'   
		-- Output is 'frozen' until the next SAMPLE_CLK_OUT.
		-- Latency is 6 CLKs
		-- Radix2
		-- 	1st Radix 2 butterfly output (X2A + j*Y2A), (X2B + j*Y2B)
		--		x2a = xa + xb
		-- 	y2a = ya + yb
		--		x2b = (xa-xb)*Cb + (ya-yb)*Sb 
		--		y2b = (ya-yb)*Cb - (xa-xb)*Sb
		-- 	2nd Radix 2 butterfly output (X2C + J*Y2C), (X2D + j*Y2D)   
		-- Radix4:
		-- x2a = xa + xb + xc + xd
		-- y2a = ya + yb + yc + yd
		-- x2b = (xa + yb - xc -yd)*Cb - (ya - xb - yc + xd)*(-Sb)
		-- y2b = (ya - xb + xc -xd)*Cb + (xa + xb - xc - yd)*(-Sb)
		-- etc.. see code below
		X2A: out std_logic_vector(17 downto 0);
		X2B: out std_logic_vector(17 downto 0);
		X2C: out std_logic_vector(17 downto 0);
		X2D: out std_logic_vector(17 downto 0);
		Y2A: out std_logic_vector(17 downto 0);
		Y2B: out std_logic_vector(17 downto 0);
		Y2C: out std_logic_vector(17 downto 0);
		Y2D: out std_logic_vector(17 downto 0);

		SAMPLE_CLK_OUT: out std_logic;
			-- indicates when output is ready
			-- Latency is 6 CLKs.

		--// CONTROLS
		RADIX2_4N: in std_logic;

		--// Overflow Monitoring
		OVERFLOW: out std_logic

 );
end entity;  

architecture BEHAVIOR of FFT_RADIX2_4 is   
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
component MULT18X18SIGNED is port( 
	A	: in STD_LOGIC_VECTOR (17 downto 0);
   B	: in STD_LOGIC_VECTOR (17 downto 0);
	P : out STD_LOGIC_VECTOR (35 downto 0) 
	);
end component;
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- Suffix _E is for precision extended
-- Suffix _D for delay
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';
signal SAMPLE_CLK_IN_D5: std_logic := '0';
signal SAMPLE_CLK_IN_D6: std_logic := '0';

signal CB_D: std_logic_vector(17 downto 0) := (others => '0');
signal CC_D: std_logic_vector(17 downto 0) := (others => '0');
signal CD_D: std_logic_vector(17 downto 0) := (others => '0');
signal SB_D: std_logic_vector(17 downto 0) := (others => '0');
signal SC_D: std_logic_vector(17 downto 0) := (others => '0');
signal SD_D: std_logic_vector(17 downto 0) := (others => '0');
signal A1: std_logic_vector(18 downto 0) := (others => '0');
signal B1: std_logic_vector(18 downto 0) := (others => '0');
signal C1: std_logic_vector(18 downto 0) := (others => '0');
signal D1: std_logic_vector(18 downto 0) := (others => '0');
signal A1_D: std_logic_vector(18 downto 0) := (others => '0');
signal B1_D: std_logic_vector(18 downto 0) := (others => '0');
signal C1_D: std_logic_vector(18 downto 0) := (others => '0');
signal D1_D: std_logic_vector(18 downto 0) := (others => '0');

-- Multiplier inputs
signal AMULT1: std_logic_vector(19 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal AMULT2: std_logic_vector(19 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal AMULT3: std_logic_vector(19 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal BMULT1: std_logic_vector(17 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal BMULT2: std_logic_vector(17 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal BMULT3: std_logic_vector(17 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal BMULT4: std_logic_vector(17 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal BMULT5: std_logic_vector(17 downto 0) := (others => '0'); 	-- multiplier input, 2's complement
signal BMULT6: std_logic_vector(17 downto 0) := (others => '0'); 	-- multiplier input, 2's complement

-- Multiplier products
signal PROD1: std_logic_vector(35 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD2: std_logic_vector(35 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD3: std_logic_vector(35 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD4: std_logic_vector(35 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD5: std_logic_vector(35 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD6: std_logic_vector(35 downto 0) := (others => '0'); 	-- multiplier output, 2's complement

signal PROD1_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD1_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD2_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD2_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD3_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD3_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD4_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD4_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD5_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD5_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD6_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD6_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD7_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD7_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD8_00: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement
signal PROD8_01: std_logic_vector(20 downto 0) := (others => '0'); 	-- multiplier output, 2's complement

signal RADIX2_4N_D: std_logic := '0';
signal RADIX2_4N_D2: std_logic := '0';
signal RADIX2_4N_D3: std_logic := '0';

signal OVERFLOW1: std_logic := '0';
signal OVERFLOW2: std_logic := '0';
signal OVERFLOW3: std_logic := '0';
signal OVERFLOW4: std_logic := '0';
signal OVERFLOW5: std_logic := '0';
signal OVERFLOW6: std_logic := '0';
signal OVERFLOW7: std_logic := '0';
signal OVERFLOW8: std_logic := '0';

signal X2A_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal X2B_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal X2C_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal X2D_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal Y2A_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal Y2B_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal Y2C_LOCAL: std_logic_vector(20 downto 0) := (others => '0');
signal Y2D_LOCAL: std_logic_vector(20 downto 0) := (others => '0');

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

--// compute signal clock phase
-- 0,1,2,3,3,3,3,3 until next cycle
CLK_PHASE_GEN_001: process(CLK)
begin
	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_IN_D6 <= SAMPLE_CLK_IN_D5;
	end if;
end process;

--// first order of business, reclock all inputs
RECLOCK_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') then
			CB_D <= CB;
			CC_D <= CC;
			CD_D <= CD;
			SB_D <= SB;
			SC_D <= SC;
			SD_D <= SD;
			RADIX2_4N_D <= RADIX2_4N;
		end if;
	end if;
end process;

--// select operands for the first group of adders A+B+C+D+2
SELECT_INPUT_ADD001: process(CLK)
begin    
-- Radix 4
-- phase 0: ((xa-xc)+(yb-yd))*Cb or -Sb; ((ya-yc)+(xd-xb))*Cb or -Sb ; 
--          ((xa-xc)-(yb-yd))*Cd or -Sd; ((ya-yc)-(xd-xb))*Cd or -Sd
-- phase 1: ((xa+xc)-(xb+xd))*Cc or -Sc; ((ya+yc)-(yb+yd))*Cc or -Sc
--				((xa+xc)+(xb+xd))          ; ((ya+yc)+(yb+yd))
-- Radix 2
-- phase 0: (xa + xb), (ya + yb); (xa-xb)*Cb ; (ya-yb)*Sb; (ya-yb)*Cb ; -(xa-xb)*Sb
-- phase 1: (xc + xd), (yc + yd); (xc-xd)*Cd ; (yc-yd)*Sd; (yc-yd)*Cd ; -(xc-xd)*Sd
	if rising_edge(CLK) then
		if(RADIX2_4N = '0') then
		-- Radix 4
			if(SAMPLE_CLK_IN = '1') then
				-- first phase	
				A1 <= (X1A(17) & X1A) - (X1C(17) & X1C);
				B1 <= (Y1B(17) & Y1B) - (Y1D(17) & Y1D);
				C1 <= (Y1A(17) & Y1A) - (Y1C(17) & Y1C);
				D1 <= (X1D(17) & X1D) - (X1B(17) & X1B); 
			elsif(SAMPLE_CLK_IN_D = '1') then
				A1 <= (X1A(17) & X1A) + (X1C(17) & X1C);
				B1 <= (X1B(17) & X1B) + (X1D(17) & X1D); 
				C1 <= (Y1A(17) & Y1A) + (Y1C(17) & Y1C);
				D1 <= (Y1B(17) & Y1B) + (Y1D(17) & Y1D); 
			end if;
		else
			-- Radix 2
			if(SAMPLE_CLK_IN = '1') then
				A1 <= (X1A(17) & X1A) + (X1B(17) & X1B);
				B1 <= (Y1A(17) & Y1A) + (Y1B(17) & Y1B);
				C1 <= (X1A(17) & X1A) - (X1B(17) & X1B);
				D1 <= (Y1A(17) & Y1A) - (Y1B(17) & Y1B); 
			elsif(SAMPLE_CLK_IN_D = '1') then
				A1 <= (X1C(17) & X1C) + (X1D(17) & X1D);
				B1 <= (Y1C(17) & Y1C) + (Y1D(17) & Y1D);
				C1 <= (X1C(17) & X1C) - (X1D(17) & X1D);
				D1 <= (Y1C(17) & Y1C) - (Y1D(17) & Y1D); 
			end if;
	 	end if;
  	end if;
end process;   

RECLOCK_00X: process(CLK)
begin
	if rising_edge(CLK) then
		A1_D <= A1;
		B1_D <= B1;
		C1_D <= C1;
		D1_D <= D1;
	end if;
end process;


-- Radix 4
-- phase 0: ((xa-xc)+(yb-yd))*Cb or -Sb; ((ya-yc)+(xd-xb))*Cb or -Sb ; 
--          ((xa-xc)-(yb-yd))*Cd or -Sd; ((ya-yc)-(xd-xb))*Cd or -Sd
-- phase 1: ((xa+xc)-(xb+xd))*Cc or -Sc; ((ya+yc)-(yb+yd))*Cc or -Sc
--				((xa+xc)+(xb+xd))          ; ((ya+yc)+(yb+yd))
-- Radix 2
-- phase 0: (xa + xb), (ya + yb); (xa-xb)*Cb ; (ya-yb)*Sb; (ya-yb)*Cb ; -(xa-xb)*Sb
-- phase 1: (xc + xd), (yc + yd); (xc-xd)*Cd ; (yc-yd)*Sd; (yc-yd)*Cd ; -(xc-xd)*Sd


PRODUCTS_001: process(CLK)
begin
	if rising_edge(CLK) then
		RADIX2_4N_D2 <= RADIX2_4N_D;

		if(RADIX2_4N_D = '0') then
			-- radix 4
			if(SAMPLE_CLK_IN_D = '1') then
				AMULT1 <= ((A1(18) & A1) + (B1(18) & B1));	-- ((xa-xc)+(yb-yd))	
				AMULT2 <= ((C1(18) & C1) + (D1(18) & D1));	-- ((ya-yc)+(xd-xb))	
				AMULT3 <= ((A1(18) & A1) - (B1(18) & B1));	-- ((xa-xc)-(yb-yd))	
			elsif(SAMPLE_CLK_IN_D2 = '1') then
				AMULT1 <= ((A1(18) & A1) - (B1(18) & B1));	-- ((xa+xc)-(xb+xd))	
				AMULT2 <= ((C1(18) & C1) - (D1(18) & D1));	-- ((ya+yc)-(yb+yd))
				AMULT3 <= ((C1_D(18) & C1_D) - (D1_D(18) & D1_D));	-- ((ya-yc)-(xd-xb))	
			end if;
		else
			-- radix 2
			if(SAMPLE_CLK_IN_D = '1') then
				AMULT1 <= C1 & "0";	-- (xa-xb)	
				AMULT2 <= D1 & "0";	-- (ya-yb)
			elsif(SAMPLE_CLK_IN_D2 = '1') then
				AMULT1 <= C1 & "0";	-- (xc-xd)	
				AMULT2 <= D1 & "0";	-- (yc-yd)
			end if;
		end if;
  	end if;
end process;

--// select multiplier coefficients
-- Do the sign later.
MUX_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(RADIX2_4N_D = '0') then
			BMULT5 <= CD_D;	-- ((xa-xc)-(yb-yd))*Cd then ((ya-yc)-(xd-xb))*Cd
			BMULT6 <= SD_D;	-- ((xa-xc)-(yb-yd))*Sd then ((ya-yc)-(xd-xb))*Sd
			if(SAMPLE_CLK_IN_D = '1') then
				BMULT1 <= CB_D;	-- ((xa-xc)+(yb-yd))*Cb	
				BMULT2 <= SB_D;	-- ((xa-xc)+(yb-yd))*Sb
				BMULT3 <= CB_D;   -- ((ya-yc)+(xd-xb))*Cb
				BMULT4 <= SB_D;	-- ((ya-yc)+(xd-xb))*Sb
			elsif(SAMPLE_CLK_IN_D2 = '1') then
				BMULT1 <= CC_D;	-- ((xa+xc)-(xb+xd))*Cc	
				BMULT2 <= SC_D;	-- ((xa+xc)-(xb+xd))*Sc
				BMULT3 <= CC_D;   -- ((ya+yc)-(yb+yd))*Cc
				BMULT4 <= SC_D;	-- ((ya+yc)-(yb+yd))*Sc
			end if;
		else
			-- radix 2
			BMULT5 <= (others => '0');
			BMULT6 <= (others => '0');
			if(SAMPLE_CLK_IN_D = '1') then
				BMULT1 <= CB_D;	-- (xa-xb)*Cb
				BMULT2 <= SB_D;	-- (xa-xb)*Sb
				BMULT3 <= SB_D;	-- (ya-yb)*Sb
				BMULT4 <= CB_D;	-- (ya-yb)*Cb
			elsif(SAMPLE_CLK_IN_D2 = '1') then
				BMULT1 <= CD_D;	-- (xc-xd)*Cd
				BMULT2 <= SD_D;	-- (xc-xd)*Sd
				BMULT3 <= SD_D;	-- (yc-yd)*Sd
				BMULT4 <= CD_D;	-- (yc-yd)*Cd
			end if;
		end if;
	end if;
end process;

--// MULTIPLIERS, 6 multipliers, 2 phases 
MULT_001: MULT18X18SIGNED port map(A => AMULT1(19 downto 2), B => BMULT1, P => PROD1);
	-- Radix-4 phase 0: ((xa-xc)+(yb-yd))*Cb   phase1: ((xa+xc)-(xb+xd))*Cc
	-- Radix-2 phase 0: (xa-xb)*Cb             phase1: (xc-xd)*Cd
MULT_002: MULT18X18SIGNED port map(A => AMULT1(19 downto 2), B => BMULT2, P => PROD2);
	-- Radix-4 phase 0: ((xa-xc)+(yb-yd))*Sb   phase1: ((xa+xc)-(xb+xd))*Sc
	-- Radix-2 phase 0: (xa-xb)*Sb             phase1: (xc-xd)*Sd
MULT_003: MULT18X18SIGNED port map(A => AMULT2(19 downto 2), B => BMULT3, P => PROD3);
	-- Radix-4 phase 0: ((ya-yc)+(xd-xb))*Cb   phase1: ((ya+yc)-(yb+yd))*Cc
	-- Radix-2 phase 0: (ya-yb)*Sb             phase1: (yc-yd)*Sd
MULT_004: MULT18X18SIGNED port map(A => AMULT2(19 downto 2), B => BMULT4, P => PROD4);
	-- Radix-4 phase 0: ((ya-yc)+(xd-xb))*Sb   phase1: ((ya+yc)-(yb+yd))*Sc
	-- Radix-2 phase 0: (ya-yb)*Cb             phase1: (yc-yd)*Cd
MULT_005: MULT18X18SIGNED port map(A => AMULT3(19 downto 2), B => BMULT5, P => PROD5);
	-- Radix-4 phase 0: ((xa-xc)-(yb-yd))*Cd   phase1: ((ya-yc)-(xd-xb))*Cd
	-- Radix-2: unused
MULT_006: MULT18X18SIGNED port map(A => AMULT3(19 downto 2), B => BMULT6, P => PROD6);
	-- Radix-4 phase 0: ((xa-xc)-(yb-yd))*Sd   phase1: ((ya-yc)-(xd-xb))*Sd
	-- Radix-2: unused

-- Store all products
RECLOCK_003: process(CLK)
begin
	if rising_edge(CLK) then
		RADIX2_4N_D3 <= RADIX2_4N_D2;

		if(SAMPLE_CLK_IN_D2 = '1') then
			PROD1_00 <= PROD1(35 downto 15);
			PROD2_00 <= PROD2(35 downto 15);
			PROD3_00 <= PROD3(35 downto 15);
			PROD4_00 <= PROD4(35 downto 15);
			PROD5_00 <= PROD5(35 downto 15);
			PROD6_00 <= PROD6(35 downto 15);
			if(RADIX2_4N_D2 = '0') then
				-- Radix-4
				-- Scaled to match the gain through the multipler when the coefficients
				-- are 1.0
				PROD7_00 <= ((A1_D(18) & A1_D(18) & A1_D) + (B1_D(18) & B1_D(18) & B1_D));		
				PROD8_00 <= ((C1_D(18) & C1_D(18) & C1_D) + (D1_D(18) & D1_D(18) & D1_D));
			else
				-- Radix-2
				-- Scaled to match the gain through the multipler when the coefficients
				-- are 1.0
				PROD7_00 <= A1_D(18) & A1_D & "0";
				PROD8_00 <= B1_D(18) & B1_D & "0";
			end if;
		end if;

		if(SAMPLE_CLK_IN_D3 = '1') then
			PROD1_01 <= PROD1(35 downto 15);
			PROD2_01 <= PROD2(35 downto 15);
			PROD3_01 <= PROD3(35 downto 15);
			PROD4_01 <= PROD4(35 downto 15);
			PROD5_01 <= PROD5(35 downto 15);
			PROD6_01 <= PROD6(35 downto 15);
			if(RADIX2_4N_D2 = '0') then
				-- Radix-4
				-- Scaled to match the gain through the multipler when the coefficients
				-- are 1.0
				PROD7_01 <= ((A1_D(18) & A1_D(18) & A1_D) + (B1_D(18) & B1_D(18) & B1_D));		
				PROD8_01 <= ((C1_D(18) & C1_D(18) & C1_D) + (D1_D(18) & D1_D(18) & D1_D));
			else
				-- Radix-2
				-- Scaled to match the gain through the multipler when the coefficients
				-- are 1.0
				PROD7_01 <= A1_D(18) & A1_D & "0";
				PROD8_01 <= B1_D(18) & B1_D & "0";
			end if;
		end if;
 	end if;
end process;

-- Prepare the output samples
OUTPUT_GEN_001: process(CLK)
begin
 	if rising_edge(CLK) then
		if(RADIX2_4N_D3 = '0') then
			-- Radix-4
			X2A_LOCAL <= PROD7_01;   	       -- (xa + xb + xc + xd)
			Y2A_LOCAL <= PROD8_01;             -- (ya + yb + yc + yd)
			X2B_LOCAL <= PROD1_00 + PROD4_00;  -- ((xa-xc)+(yb-yd))*Cb - ((ya-yc)+(xd-xb))*(-Sb)
			Y2B_LOCAL <= PROD3_00 - PROD2_00;  -- ((ya-yc)+(xd-xb))*Cb + ((xa-xc)+(yb-yd))*(-Sb)
			X2C_LOCAL <= PROD1_01 + PROD4_01;  -- ((xa+xc)-(xb+xd))*Cc - ((ya+yc)-(yb+yd))*(-Sc)
			Y2C_LOCAL <= PROD3_01 - PROD2_01;  -- ((ya+yc)-(yb+yd))*Cc + ((xa+xc)-(xb+xd))*(-Sc)
			X2D_LOCAL <= PROD5_00 + PROD6_01;  -- ((xa-xc)-(yb-yd))*Cd - ((ya-yc)-(xd-xb))*(-Sd)
			Y2D_LOCAL <= PROD5_01 - PROD6_00;  -- ((ya-yc)-(xd-xb))*Cd + ((xa-xc)-(yb-yd))*(-Sd)
		else
			-- Radix 2
			X2A_LOCAL <= PROD7_00;
			Y2A_LOCAL <= PROD8_00;
			X2B_LOCAL <= PROD1_00 + PROD3_00;	--		x2b = (xa-xb)*Cb + (ya-yb)*Sb
			Y2B_LOCAL <= PROD4_00 - PROD2_00;	--		y2b = (ya-yb)*Cb - (xa-xb)*Sb
			X2C_LOCAL <= PROD7_01;
			Y2C_LOCAL <= PROD8_01;
			X2D_LOCAL <= PROD1_01 + PROD3_01;	--		x2d = (xc-xd)*Cd + (yc-yd)*Sd
			Y2D_LOCAL <= PROD4_01 - PROD2_01;	--		y2d = (yc-yd)*Cd - (xc-xd)*Sd
		end if;
	end if;
end process;
  		 
		


-- Shift and detect overflow
CLAMP_X2A: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (X2A_LOCAL(20) = '0') and (
				((X2A_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((X2A_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((X2A_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					X2A <= "011111111111111111";
					OVERFLOW1 <= '1';
			elsif (X2A_LOCAL(20) = '1') and (
				((X2A_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((X2A_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((X2A_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					X2A <= "100000000000000001";
					OVERFLOW1 <= '1';
			else
				OVERFLOW1 <= '0';
				if(OUTPUT_SHIFT = 0) then
					X2A <= X2A_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					X2A <= X2A_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					X2A <= X2A_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					X2A <= X2A_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_Y2A: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (Y2A_LOCAL(20) = '0') and (
				((Y2A_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((Y2A_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2A_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					Y2A <= "011111111111111111";
					OVERFLOW2 <= '1';
			elsif (Y2A_LOCAL(20) = '1') and (
				((Y2A_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((Y2A_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2A_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					Y2A <= "100000000000000001";
					OVERFLOW2 <= '1';
			else
				OVERFLOW2 <= '0';
				if(OUTPUT_SHIFT = 0) then
					Y2A <= Y2A_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					Y2A <= Y2A_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					Y2A <= Y2A_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					Y2A <= Y2A_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_X2B: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (X2B_LOCAL(20) = '0') and (
				((X2B_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((X2B_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((X2B_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					X2B <= "011111111111111111";
					OVERFLOW3 <= '1';
			elsif (X2B_LOCAL(20) = '1') and (
				((X2B_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((X2B_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((X2B_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					X2B <= "100000000000000001";
					OVERFLOW3 <= '1';
			else
				OVERFLOW3 <= '0';
				if(OUTPUT_SHIFT = 0) then
					X2B <= X2B_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					X2B <= X2B_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					X2B <= X2B_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					X2B <= X2B_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_Y2B: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (Y2B_LOCAL(20) = '0') and (
				((Y2B_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((Y2B_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2B_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					Y2B <= "011111111111111111";
					OVERFLOW4 <= '1';
			elsif (Y2B_LOCAL(20) = '1') and (
				((Y2B_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((Y2B_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2B_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					Y2B <= "100000000000000001";
					OVERFLOW4 <= '1';
			else
				OVERFLOW4 <= '0';
				if(OUTPUT_SHIFT = 0) then
					Y2B <= Y2B_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					Y2B <= Y2B_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					Y2B <= Y2B_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					Y2B <= Y2B_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_X2C: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (X2C_LOCAL(20) = '0') and (
				((X2C_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((X2C_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((X2C_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					X2C <= "011111111111111111";
					OVERFLOW5 <= '1';
			elsif (X2C_LOCAL(20) = '1') and (
				((X2C_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((X2C_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((X2C_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					X2C <= "100000000000000001";
					OVERFLOW5 <= '1';
			else
				OVERFLOW5 <= '0';
				if(OUTPUT_SHIFT = 0) then
					X2C <= X2C_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					X2C <= X2C_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					X2C <= X2C_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					X2C <= X2C_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_Y2C: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (Y2C_LOCAL(20) = '0') and (
				((Y2C_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((Y2C_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2C_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					Y2C <= "011111111111111111";
					OVERFLOW6 <= '1';
			elsif (Y2C_LOCAL(20) = '1') and (
				((Y2C_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((Y2C_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2C_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					Y2C <= "100000000000000001";
					OVERFLOW6 <= '1';
			else
				OVERFLOW6 <= '0';
				if(OUTPUT_SHIFT = 0) then
					Y2C <= Y2C_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					Y2C <= Y2C_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					Y2C <= Y2C_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					Y2C <= Y2C_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_X2D: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (X2D_LOCAL(20) = '0') and (
				((X2D_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((X2D_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((X2D_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					X2D <= "011111111111111111";
					OVERFLOW7 <= '1';
			elsif (X2D_LOCAL(20) = '1') and (
				((X2D_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((X2D_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((X2D_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					X2D <= "100000000000000001";
					OVERFLOW7 <= '1';
			else
				OVERFLOW7 <= '0';
				if(OUTPUT_SHIFT = 0) then
					X2D <= X2D_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					X2D <= X2D_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					X2D <= X2D_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					X2D <= X2D_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;

CLAMP_Y2D: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN_D5 = '1') then
			-- Detect positive overflow
			if (Y2D_LOCAL(20) = '0') and (
				((Y2D_LOCAL(19 downto 19) /= "0") and (OUTPUT_SHIFT = 1)) or
			  	((Y2D_LOCAL(19 downto 18) /= "00") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2D_LOCAL(19 downto 17) /= "000") and (OUTPUT_SHIFT = 3))) then
					-- positive overflow
					Y2D <= "011111111111111111";
					OVERFLOW8 <= '1';
			elsif (Y2D_LOCAL(20) = '1') and (
				((Y2D_LOCAL(19 downto 19) /= "1") and (OUTPUT_SHIFT = 1)) or
			  	((Y2D_LOCAL(19 downto 18) /= "11") and (OUTPUT_SHIFT = 2)) or 
			  	((Y2D_LOCAL(19 downto 17) /= "111") and (OUTPUT_SHIFT = 3))) then
					-- negative overflow
					Y2D <= "100000000000000001";
					OVERFLOW8 <= '1';
			else
				OVERFLOW8 <= '0';
				if(OUTPUT_SHIFT = 0) then
					Y2D <= Y2D_LOCAL(20 downto 3);
				elsif(OUTPUT_SHIFT = 1) then
					Y2D <= Y2D_LOCAL(19 downto 2);
				elsif(OUTPUT_SHIFT = 2) then
					Y2D <= Y2D_LOCAL(18 downto 1);
				else
				--elsif(OUTPUT_SHIFT = 3) then
					Y2D <= Y2D_LOCAL(17 downto 0);
				end if;
			end if;
		end if;
	end if;
end process;


-- helps next process know when to read the butterfly output     
-- Total latency for Radix 4 is 6 CLKs
SAMPLE_CLK_OUT <= '1' when (SAMPLE_CLK_IN_D6 = '1') else '0';

OVERFLOW <= OVERFLOW1 or OVERFLOW2 or OVERFLOW3 or OVERFLOW4 or OVERFLOW5 or OVERFLOW6
				or OVERFLOW7 or OVERFLOW8;

end BEHAVIOR;