----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 04/13/2021 09:59:49 PM
-- Design Name: 
-- Module Name: FFT_VecyByCirc5_DP - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

library work;
use work.Common.all;


entity DP_15_2ip is
generic ( 
	constant P_VALUE:      integer;
    constant SAMPLES_LOG2: integer := 16
); 
Port 
(
    Clk : in STD_LOGIC;
    Rst_n : in STD_LOGIC;
    
    a_data_bin: in std_logic;   
    b_data_bin: in std_logic;  
    last_frame_reg: in std_logic;
    
    
 --    INPUTS    
    fsm_ip_rst:             in std_logic;   
	
--  FFT IP Outputs
    fsm_xfft_in_tvalid:     in std_logic;
    fsm_xfft_out_tready:    in std_logic;
    fsm_xfft_config_tvalid: in std_logic;
    
--   IFFT Outputs    
    fsm_xifft_in_tlast:      in std_logic;  
    fsm_xifft_in_tvalid:     in std_logic;

    fsm_xifft_out_tready:    in std_logic;
    fsm_xifft_config_tvalid: in std_logic;
	
--   Counter out Signals
    fsm_cnt_en:  in std_logic;
    fsm_cnt_rst: in std_logic;    
--     SRAM OUTPUTS
    fsm_sram_we:       in std_logic;                        
    fsm_sram_re:       in std_logic;      
    fsm_sram_CSn:      in std_logic;                   
    fsm_sram_rst:  in std_logic; 
    fsm_sram_addr_sel: in std_logic_vector(1 downto 0);                      
    fsm_sram_data_sel: in std_logic; 
--    General Signals
    fsm_out_en:        in std_logic;
    fsm_use_ifft_sram: in std_logic;
	
--  FFT input MUX
-- 1 mean we are using the FFT IPS for FFT, 0 for IFFT
	fsm_in_fft_mux_sel: in std_logic;
    
-- DP out SIgnals
    dp_cnt_tc:             out std_logic;
	dp_cnt_pad_tc:         out std_logic;
	
-- FFT Input Control Signals
    dp_xfft_config_tready:  out std_logic;
    dp_xifft_config_tready:  out std_logic;
    
-- FFT out tvalid    
    dp_xfft_out_tvalid:      out std_logic;
    dp_xifft_out_tvalid:    out std_logic;
    
    dp_xfft_in_tready:      out std_logic;
    dp_xifft_in_tready:      out std_logic;
    
--    CMUL Signals
    dp_cmpy_out_tlast:      out std_logic;
    dp_cmpy_out_tvalid:     out std_logic;
--     IFFT Input Control Signals    
    dp_xfft_out_tlast:      out std_logic;
    dp_xifft_out_tlast:      out std_logic;
    dp_has_both_fft_data:    out std_logic;
-- DP Output:
    dp_out_bin: out std_logic;
    dp_out_int: out std_logic_vector((3+SAMPLES_LOG2)-1 downto 0)
);
end DP_15_2ip;

architecture Behavioral of DP_15_2ip is
    constant IN_WIDTH:     integer := 16;
		
    constant CONFIG_WIDTH: integer := 24;
    constant USER_WIDTH: integer := 16;
    constant COMP_OUT_WIDTH: integer := 18; 
    constant EXT_CMUL_OUT_WIDTH: integer := 96;
    constant RAM_IN_WIDTH: integer := 66;
    constant EXT_IP_IN_WIDTH: integer := 48;
   
 -- Extend the input!  
    constant EXT_BITS_NUM: integer := 4;
    constant EXT_IN_WIDTH: integer := IN_WIDTH+EXT_BITS_NUM;
       
-- Null Imaginary Frame data
    constant NULL_IMAG_PART: std_logic_vector(IN_WIDTH-1 downto 0) := (others => '0');
   
-- Convert binary input to frame inoput, IN_WIDTH bits   
    constant ONE_FRAME_BITS: std_logic_vector(IN_WIDTH-1 downto 0) := ('0', others => '1'); 
    constant ZERO_FRAME_BITS: std_logic_vector(IN_WIDTH-1 downto 0) := (others => '0');  
		
-- IP Declaration
    COMPONENT IP_FFT_16_4_ext_4
    PORT (
        aclk : IN STD_LOGIC;
        aresetn : IN STD_LOGIC;
        s_axis_config_tdata : IN STD_LOGIC_VECTOR(CONFIG_WIDTH-1 DOWNTO 0);
        s_axis_config_tvalid : IN STD_LOGIC;
        s_axis_config_tready : OUT STD_LOGIC;
        s_axis_data_tdata : IN STD_LOGIC_VECTOR(EXT_IP_IN_WIDTH-1 DOWNTO 0);
        s_axis_data_tvalid : IN STD_LOGIC;
        s_axis_data_tready : OUT STD_LOGIC;
        s_axis_data_tlast : IN STD_LOGIC;
        m_axis_data_tdata : OUT STD_LOGIC_VECTOR(EXT_IP_IN_WIDTH-1 DOWNTO 0);
        m_axis_data_tuser : OUT STD_LOGIC_VECTOR(USER_WIDTH-1 DOWNTO 0);
        m_axis_data_tvalid : OUT STD_LOGIC;
        m_axis_data_tready : IN STD_LOGIC;
        m_axis_data_tlast : OUT STD_LOGIC;
        event_frame_started : OUT STD_LOGIC;
        event_tlast_unexpected : OUT STD_LOGIC;
        event_tlast_missing : OUT STD_LOGIC;
        event_status_channel_halt : OUT STD_LOGIC;
        event_data_in_channel_halt : OUT STD_LOGIC;
        event_data_out_channel_halt : OUT STD_LOGIC
      );
    END COMPONENT;
    
    COMPONENT IP_FFT_16_5
    PORT (
        aclk : IN STD_LOGIC;
        aresetn : IN STD_LOGIC;
        s_axis_config_tdata : IN STD_LOGIC_VECTOR(CONFIG_WIDTH-1 DOWNTO 0);
        s_axis_config_tvalid : IN STD_LOGIC;
        s_axis_config_tready : OUT STD_LOGIC;
        
        s_axis_data_tdata : IN STD_LOGIC_VECTOR(79 DOWNTO 0);
        s_axis_data_tvalid : IN STD_LOGIC;
        s_axis_data_tready : OUT STD_LOGIC;
        s_axis_data_tlast : IN STD_LOGIC;
        
        m_axis_data_tdata : OUT STD_LOGIC_VECTOR(79 DOWNTO 0);
        m_axis_data_tuser : OUT STD_LOGIC_VECTOR(USER_WIDTH-1 DOWNTO 0);
        m_axis_data_tvalid : OUT STD_LOGIC;
        m_axis_data_tready : IN STD_LOGIC;
        m_axis_data_tlast : OUT STD_LOGIC;
        event_frame_started : OUT STD_LOGIC;
        event_tlast_unexpected : OUT STD_LOGIC;
        event_tlast_missing : OUT STD_LOGIC;
        event_status_channel_halt : OUT STD_LOGIC;
        event_data_in_channel_halt : OUT STD_LOGIC;
        event_data_out_channel_halt : OUT STD_LOGIC
      );
    END COMPONENT;
    
    COMPONENT IP_CMUL_4_ext_4
    PORT 
    (
        aclk : IN STD_LOGIC;
        aresetn : IN STD_LOGIC;
        s_axis_a_tvalid : IN STD_LOGIC;
        s_axis_a_tlast : IN STD_LOGIC;
        s_axis_a_tdata : IN STD_LOGIC_VECTOR(47 DOWNTO 0);
        s_axis_b_tvalid : IN STD_LOGIC;
        s_axis_b_tlast : IN STD_LOGIC;
        s_axis_b_tdata : IN STD_LOGIC_VECTOR(47 DOWNTO 0);
        m_axis_dout_tvalid : OUT STD_LOGIC;
        m_axis_dout_tlast : OUT STD_LOGIC;
        m_axis_dout_tdata : OUT STD_LOGIC_VECTOR(EXT_CMUL_OUT_WIDTH-1 DOWNTO 0)
    );
    END COMPONENT;
       
    COMPONENT IP_BRAM_16
    PORT (
      clka : IN STD_LOGIC;
      rsta : IN STD_LOGIC;
      wea : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
      addra : IN STD_LOGIC_VECTOR(SAMPLES_LOG2-1 DOWNTO 0);
      dina : IN STD_LOGIC_VECTOR(65 DOWNTO 0);
      douta : OUT STD_LOGIC_VECTOR(65 DOWNTO 0);
      rsta_busy : OUT STD_LOGIC
    );
    END COMPONENT;
    
-- Data Path Components    
    component Counter is
    generic (constant N: integer := 8);
    port 
    ( 
         Rst_n : in std_logic;
         Clk : in std_logic;
         En : in std_logic;
         CntRst: in std_logic; -- When 1 reset the counte to 0 sync reset.
         CntValue : out unsigned(N-1 downto 0);
         TC : out std_logic
     );
     end component;


    component RegN is
    generic (N: integer := 16);
    port
    (
        CLK:     in     std_logic;
        Rst_n:   in     std_logic;
        En:      in     std_logic;
        D:       in     std_logic_vector(N-1 downto 0);
        Q:       out std_logic_vector(N-1 downto 0)
    );
    end component;
    
    component Reg1 is
    port
    (
        CLK:    in     std_logic;
        Rst_n:    in     std_logic;
        En:        in     std_logic;
        D:        in     std_logic;
        Q:        out std_logic
    );
    end component;
       
            
    component ADR_GEN is
    generic (DEPTH: integer);
    Port 
    ( 
        Clk:        in std_logic;
        Rst_n:      in std_logic;
        sel:         in adr_sel;
        sram_we:     in std_logic;
        ifft_idx:  in std_logic_vector(DEPTH-1 downto 0); 
        cnt_value:   in std_logic_vector(DEPTH-1 downto 0);
        ifft_mode: in std_logic := '0';
        out_addr: out std_logic_vector(DEPTH-1 downto 0)
    );
    end component;
    
        
    component OutConverter is
    generic (
        constant SAMPLES_LOG2: integer := 5
    );
    port
    (
        Clk: in std_logic; Rst_n: in std_logic;
        in_data: in std_logic_vector(32 downto 0);
        out_data_bin: out std_logic;
        out_data_int: out std_logic_vector((3+SAMPLES_LOG2)-1 downto 0)
               := (others => '0')
    );
    end component;
         
----    
---- DP Signals
----

---    
--- FFT Signals
---
	signal a_data_frame: std_logic_vector(IN_WIDTH-1 downto 0);
	signal b_data_frame: std_logic_vector(IN_WIDTH-1 downto 0);

-- TODO: Eventually we should use this??
    signal dp_xfft_a_in_tready, dp_xfft_b_in_tready: std_logic;
    
    --- A FFT
    -- signal dp_xfft_a_out_tdata: std_logic_vector(2*COMP_OUT_WIDTH-1 downto 0);
    signal dp_xfft_a_out_tdata: std_logic_vector(EXT_IP_IN_WIDTH-1 downto 0);
	signal dp_xfft_a_out_tdata_ext: std_logic_vector(37 downto 0);
	
    --- B FFT
	signal dp_xfft_b_data_in: std_logic_vector(EXT_IP_IN_WIDTH-1 downto 0);
	
    signal dp_xfft_b_out_tuser: std_logic_vector(USER_WIDTH-1 downto 0);
    signal dp_xfft_b_out_tdata: std_logic_vector(EXT_IP_IN_WIDTH-1 downto 0);
    
    signal dp_xfft_config_tdata: std_logic_vector(CONFIG_WIDTH-1 downto 0);
    
    signal dp_xfft_b_event_frame_started       : std_logic;
    signal dp_xfft_b_event_tlast_unexpected    : std_logic;
    signal dp_xfft_b_event_tlast_missing       : std_logic;
    signal dp_xfft_b_event_status_channel_halt : std_logic;
    signal dp_xfft_b_event_data_in_channel_halt: std_logic;
    signal dp_xfft_b_event_data_out_channel_halt: std_logic;  
    
-- Complex Multiplier   
	constant MUL_COMP_OUT_WIDTH: integer := 33;
    constant EXT_MUL_COMP_OUT_WIDTH: integer := 41;
	
    signal dp_cmpy_out_tdata_ext: std_logic_vector(95 downto 0); 
    signal mul_out_re, mul_out_im: std_logic_vector(EXT_MUL_COMP_OUT_WIDTH-1 downto 0);
   
---    
--- SRAM
---
    signal dp_sram_rst: std_logic;
    signal dp_sram_addr: std_logic_vector(SAMPLES_LOG2-1 downto 0);
    signal dp_sram_addr_corr: std_logic_vector(SAMPLES_LOG2-1 downto 0);
    signal dp_sram_data_in, dp_sram_data_out: std_logic_vector(RAM_IN_WIDTH-1 downto 0);

-- IP  BRAM
    signal dp_blk_rst: std_logic;
    signal dp_blk_mem_we: std_logic_vector(0 downto 0);
    signal dp_blk_mem_adr: std_logic_vector(SAMPLES_LOG2-1 downto 0);
    signal dp_blk_mem_out: std_logic_vector(RAM_IN_WIDTH-1 downto 0);
    signal dp_blk_rst_busy: std_logic;
---
--- IFFT
---

    signal fft_config_tdata: std_logic_vector(CONFIG_WIDTH-1 downto 0);
    signal ifft_config_tdata: std_logic_vector(CONFIG_WIDTH-1 downto 0);
    signal xifft_config_tdata: std_logic_vector(CONFIG_WIDTH-1 downto 0);
    
    signal dp_ifft_out_tdata: std_logic_vector(79 downto 0);
    signal dp_ifft_out_tuser: std_logic_vector(USER_WIDTH-1 downto 0);

    signal xifft_in_tdata, xifft_out_tdata: std_logic_vector(79 downto 0);
    signal xifft_out_tuser: std_logic_vector(USER_WIDTH-1 downto 0);

	signal xifft_out_tvalid, xifft_out_tlast: std_logic;
    signal xfft_out_tready,  xfft_out_tvalid, xfft_out_tlast: std_logic;
    
	signal xfft_b_config_tready: std_logic;
    
    signal xifft_event_frame_started       : std_logic;
    signal xifft_event_tlast_unexpected    : std_logic;
    signal xifft_event_tlast_missing       : std_logic;
    signal xifft_event_status_channel_halt : std_logic;
    signal xifft_event_data_in_channel_halt: std_logic;
    signal xifft_event_data_out_channel_halt: std_logic; 
    
    signal xifft_in_tlast: std_logic;
    
-- Internal signals  
    signal out_data: std_logic_vector(RAM_IN_WIDTH-1 downto 0);
    signal cnt_value: unsigned(SAMPLES_LOG2-1 downto 0); 
    signal ifft_idx: std_logic_vector(SAMPLES_LOG2-1 downto 0);     
        
---
---  DEBUG Signals
---  
    constant FFT_OUT_WIDTH: integer := 16;
    signal DEBUG_a_data_re, DEBUG_a_data_im: std_logic_vector(FFT_OUT_WIDTH-1 downto 0);
    signal DEBUG_b_data_re, DEBUG_b_data_im: std_logic_vector(FFT_OUT_WIDTH-1 downto 0);
    signal DEBUG_mul_data_re, DEBUG_mul_data_im:  std_logic_vector(FFT_OUT_WIDTH-1 downto 0);
    
    signal DEBUG_scaled_cmul_out_re, DEBUG_scaled_cmul_out_im:  std_logic_vector(FFT_OUT_WIDTH-1 downto 0);
    
    signal DEBUG_cmul_out_re, DEBUG_cmul_out_im:  std_logic_vector(MUL_COMP_OUT_WIDTH-1 downto 0);
        
    signal DEBUG_ifft_in_re, DEBUG_ifft_in_im:  std_logic_vector(39 downto 0);
    signal DEBUG_ifft_out_re, DEBUG_ifft_out_im:  std_logic_vector(MUL_COMP_OUT_WIDTH-1 downto 0);
    signal DEBUG_ifft_sram_out_re, DEBUG_ifft_sram_out_im:  std_logic_vector(MUL_COMP_OUT_WIDTH-1 downto 0);
   
    signal DEBUG_sram_in_re, DEBUG_sram_in_im: std_logic_vector(32 downto 0);
    signal DEBUG_sram_out_re, DEBUG_sram_out_im: std_logic_vector(32 downto 0);
begin

-- Counter
F_IDX_CNT: Counter generic map(N => SAMPLES_LOG2) 
port map (
	Clk => Clk, Rst_n => Rst_n, 
    En => fsm_cnt_en, TC => dp_cnt_tc,
    CntValue => cnt_value,
    CntRst => fsm_cnt_rst
);

-- IPs
-- Set the FFT/IFFT Config data, it is always present because we are not doing any 
-- multi channel thing or changing the FFT number of samples
-- the format is [PadBit, ScalingFactor, FFT/IFFT]  
-- FFT Transform Configuration        
fft_config_tdata  <= '0' & "1010101010101010101011" & '1'; 
-- IFFT Transform Configuration
ifft_config_tdata  <= '0' & "0000000000000000000000" & '0'; -- (others => '0'); --- '0' & "101011" & '0'; --- 

a_data_frame <= ONE_FRAME_BITS when a_data_bin ='1' else
				NULL_IMAG_PART when a_data_bin ='0' else
				(others => '0');  
				 				 				 
b_data_frame <= ONE_FRAME_BITS when b_data_bin ='1' else
				NULL_IMAG_PART when b_data_bin ='0' else
				(others => '0');

				

dp_xfft_b_data_in(19 downto 0) <= b_data_frame & b_data_frame(0) & b_data_frame(0) & b_data_frame(0) & b_data_frame(0);
dp_xfft_b_data_in(23 downto 20) <= (others => b_data_frame(15));
dp_xfft_b_data_in(47 downto 24) <= (others => '0');				 

dp_xfft_out_tlast <= xfft_out_tlast;
dp_xfft_out_tvalid <= xfft_out_tvalid;

IP_FFT_B:  IP_FFT_16_4_ext_4  port map (
	aclk => Clk, aresetn => fsm_ip_rst,
	   -- Config AXIS Buff
    s_axis_config_tvalid        => fsm_xfft_config_tvalid,
    s_axis_config_tready        => dp_xfft_config_tready,
    s_axis_config_tdata         => dp_xfft_config_tdata,
    
    s_axis_data_tdata           => dp_xfft_b_data_in,
    s_axis_data_tlast           => last_frame_reg,
    s_axis_data_tvalid          => fsm_xfft_in_tvalid,
    s_axis_data_tready          => dp_xfft_b_in_tready,
    
    
    m_axis_data_tready          => fsm_xfft_out_tready,
    m_axis_data_tvalid          => xfft_out_tvalid,     
    m_axis_data_tdata           => dp_xfft_b_out_tdata,
    m_axis_data_tuser           => dp_xfft_b_out_tuser,
    m_axis_data_tlast           => xfft_out_tlast,
      
--  m_axis_status_tvalid        => fft_axi_status_tvalid,
--  m_axis_status_tready        => fft_axi_status_tready,
--  m_axis_status_tdata         => fft_axi_status_tdata,
--  event_fft_overflow          => event_fft_overflow,
      
    event_frame_started         => dp_xfft_b_event_frame_started,
    event_tlast_unexpected      => dp_xfft_b_event_tlast_unexpected,
    event_tlast_missing         => dp_xfft_b_event_tlast_missing,
    event_status_channel_halt   => dp_xfft_b_event_status_channel_halt,
    event_data_in_channel_halt  => dp_xfft_b_event_data_in_channel_halt,
    event_data_out_channel_halt => dp_xfft_b_event_data_out_channel_halt
);

IP_CMUL_Comp: IP_CMUL_4_ext_4 port map (
    aclk => Clk, aresetn => fsm_ip_rst,
 -- A input
    s_axis_a_tvalid    => xifft_out_tvalid,
    s_axis_a_tlast     => xifft_out_tlast,
    s_axis_a_tdata     => dp_xfft_a_out_tdata,
    
-- B Input    
    s_axis_b_tvalid    => xfft_out_tvalid,
    s_axis_b_tlast     => xfft_out_tlast,
    s_axis_b_tdata     => dp_xfft_b_out_tdata,
    
    m_axis_dout_tvalid => dp_cmpy_out_tvalid,
    m_axis_dout_tlast  => dp_cmpy_out_tlast,
    m_axis_dout_tdata  => dp_cmpy_out_tdata_ext
-- Only used when we are doing proper rounding.    
--    s_axis_ctrl_tvalid => axi_config_tvalid,
--    s_axis_ctrl_tdata  => axi_config_tdata,
);

mul_out_re <= dp_cmpy_out_tdata_ext(40 downto 0);
mul_out_im <= dp_cmpy_out_tdata_ext(88 downto 48);

dp_sram_data_in <= (others => '0') when Rst_n='0' else
-- Remove padding bits
                mul_out_im(EXT_MUL_COMP_OUT_WIDTH-1 downto EXT_MUL_COMP_OUT_WIDTH-MUL_COMP_OUT_WIDTH) & 
                mul_out_re(EXT_MUL_COMP_OUT_WIDTH-1 downto EXT_MUL_COMP_OUT_WIDTH-MUL_COMP_OUT_WIDTH) when fsm_sram_data_sel='0' else
                dp_ifft_out_tdata(72 downto 40) & dp_ifft_out_tdata(32 downto 0);

dp_sram_rst <= fsm_sram_rst and Rst_n;

-- DP Main Memory Block
ifft_idx <= dp_ifft_out_tuser(SAMPLES_LOG2-1 downto 0);

ADR_GEN_COMP: ADR_GEN generic map(DEPTH => SAMPLES_LOG2) 
 port map (
    Clk     => Clk, Rst_n => Rst_n,
-- 1 When we are doing storing ifft data we need to reaorder the inputs
    sel => fsm_sram_addr_sel,
    ifft_idx => ifft_idx,
    cnt_value  => std_logic_vector(cnt_value),
    sram_we   => fsm_sram_we,
    ifft_mode => fsm_use_ifft_sram, 
    out_addr => dp_blk_mem_adr
); 

          
dp_blk_rst <= not fsm_sram_rst;
dp_blk_mem_we(0) <= fsm_sram_we;

RAM_COMP: IP_BRAM_16 port map (
    clka  => Clk, 
    rsta  => dp_blk_rst,
    wea   => dp_blk_mem_we,
    addra => dp_blk_mem_adr,
    dina  => dp_sram_data_in,
    douta => dp_blk_mem_out,
    rsta_busy => dp_blk_rst_busy
);   

dp_sram_data_out <= dp_blk_mem_out when fsm_sram_re='1' else
                    (others => '0');


-- Recreate the IN_WIDTH output FFT frame from the bigger FFT.
dp_ifft_out_tdata   <= xifft_out_tdata when fsm_in_fft_mux_sel = '0' else (others => '0');

-- This is more complex here as we need to condifer the padding and sign extension.
-- IFFT_OUT: IM (72:40) & RE(32:0)
-- FFT_ext_out: IM() & RE() 
dp_xfft_a_out_tdata_ext <= xifft_out_tdata(55 downto 37) & xifft_out_tdata(31 downto 13) when fsm_in_fft_mux_sel='1' else 
					      (others => '0');
--IM
dp_xfft_a_out_tdata(43 downto 24) <= dp_xfft_a_out_tdata_ext(37 downto 18);
dp_xfft_a_out_tdata(47 downto 44) <= (others => dp_xfft_a_out_tdata_ext(18));
--RE
dp_xfft_a_out_tdata(18 downto 0) <= dp_xfft_a_out_tdata_ext(18 downto 0);
dp_xfft_a_out_tdata(23 downto 19) <= (others => dp_xfft_a_out_tdata_ext(18));


xifft_config_tdata <= fft_config_tdata when fsm_in_fft_mux_sel='1' else 
					  ifft_config_tdata;


-- Convert the binary input to a 16bit vector				 
ADataPad: process (Rst_n, fsm_out_en, fsm_in_fft_mux_sel, a_data_bin)
begin
    if Rst_n='0' then 
       xifft_in_tdata <= (others => '0');
    elsif fsm_in_fft_mux_sel='1' then  
-- IM	
        xifft_in_tdata(79 downto 72) <= (others => '0');
        xifft_in_tdata(72 downto 40) <= (others => '0'); 
-- RE
        xifft_in_tdata(39 downto 20) <= (others => '0');
        xifft_in_tdata(23 downto 20) <= (others => a_data_frame(15));
        xifft_in_tdata(19 downto 0) <= a_data_frame & a_data_frame(0) & a_data_frame(0) & a_data_frame(0) & a_data_frame(0);
     else
        xifft_in_tdata <= (others => '0');
		if fsm_out_en/='1' then -- When reading RAM for output, we send 0           
			xifft_in_tdata(79 downto 72) <= (others => dp_sram_data_out(65));
			xifft_in_tdata(72 downto 40) <= dp_sram_data_out(65 downto 33); 
			xifft_in_tdata(39 downto 33) <= (others => dp_sram_data_out(32));
			xifft_in_tdata(32 downto 0)  <= dp_sram_data_out(32 downto 0);
		end if;
	 end if;
end process;

dp_xifft_out_tlast <= xifft_out_tlast;
dp_xifft_out_tvalid <= xifft_out_tvalid;

xifft_in_tlast <= last_frame_reg when fsm_in_fft_mux_sel='1' else
                  fsm_xifft_in_tlast;
                  
dp_has_both_fft_data <= xfft_out_tvalid and xifft_out_tvalid;                



IP_IFFT:  IP_FFT_16_5  port map (
	aclk => Clk, aresetn => fsm_ip_rst,
	   -- Config AXIS Buff
   s_axis_config_tvalid        => fsm_xifft_config_tvalid,
   s_axis_config_tready        => dp_xifft_config_tready,
   s_axis_config_tdata         => xifft_config_tdata,
    
   s_axis_data_tdata           => xifft_in_tdata,
   s_axis_data_tlast           => xifft_in_tlast,
   s_axis_data_tvalid          => fsm_xifft_in_tvalid,
   s_axis_data_tready          => dp_xifft_in_tready,
    
  
   m_axis_data_tdata           => xifft_out_tdata,
   m_axis_data_tuser           => xifft_out_tuser,
   m_axis_data_tready          => fsm_xifft_out_tready,
    
   m_axis_data_tvalid          => xifft_out_tvalid,
   m_axis_data_tlast           => xifft_out_tlast, 
      
--  m_axis_status_tvalid        => fft_axi_status_tvalid,
--  m_axis_status_tready        => fft_axi_status_tready,
--  m_axis_status_tdata         => fft_axi_status_tdata,
--  event_fft_overflow          => event_fft_overflow,
      
   event_frame_started         => xifft_event_frame_started,
   event_tlast_unexpected      => xifft_event_tlast_unexpected,
   event_tlast_missing         => xifft_event_tlast_missing,
   event_status_channel_halt   => xifft_event_status_channel_halt,
   event_data_in_channel_halt  => xifft_event_data_in_channel_halt,
   event_data_out_channel_halt => xifft_event_data_out_channel_halt
);

out_data <= dp_sram_data_out when fsm_out_en='1' else (others => '0');

-- Convert the IFFT out into a binary sequence.
OutConvComp: OutConverter generic map(SAMPLES_LOG2 => SAMPLES_LOG2) 
port map (
    Clk => Clk, Rst_n => Rst_n,
    in_data  => out_data(32 downto 0),
    out_data_bin => dp_out_bin,
    out_data_int => dp_out_int
);

-- Detect if the dp_cnt_val is equals to the number of samples p of the system. 
-- This is used for the padding. Again argh I would like to avoid a process here...
TC_Comp: process (Clk, Rst_n, cnt_value)
begin
	if Rst_n='0' then 
		dp_cnt_pad_tc <= '0';
	else --if rising_edge(Clk) then
		dp_cnt_pad_tc <= '0';
		if to_integer(cnt_value) = P_VALUE-1 then
			dp_cnt_pad_tc <= '1';
		end if;
	end if;
end process;

---  DEBUG Signals
---  DEBUG Signals
DEBUG_ifft_out_im <= dp_ifft_out_tdata(72 downto 40);
DEBUG_ifft_out_re <= dp_ifft_out_tdata(32 downto 0);
DEBUG_ifft_sram_out_im <= out_data(65 downto 33);
DEBUG_ifft_sram_out_re <= out_data(32 downto 0);

DEBUG_cmul_out_im <= mul_out_im(40 downto 8);
DEBUG_cmul_out_re <= mul_out_re(40 downto 8);
DEBUG_a_data_im <= dp_xfft_a_out_tdata(31 downto 16);
DEBUG_a_data_re <= dp_xfft_a_out_tdata(15 downto 0);
DEBUG_b_data_im <= dp_xfft_b_out_tdata(31 downto 16);
DEBUG_b_data_re <= dp_xfft_b_out_tdata(15 downto 0);

DEBUG_sram_in_im <= dp_sram_data_in(65 downto 33);
DEBUG_sram_in_re <= dp_sram_data_in(32 downto 0);
DEBUG_sram_out_im <= dp_sram_data_out(65 downto 33);
DEBUG_sram_out_re <= dp_sram_data_out(32 downto 0);

end Behavioral;
