----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 04/01/2021 03:41:03 PM
-- Design Name: 
-- Module Name: FFT_VecByCirc_14_opt - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
--  This module implement the optimized version of the FFT_VecByCirculant were some of the SRAM used are removed and the 
--  XilinX IP comunicate using directly the AXI interface without any additional hardware. This will reduce the overall 
--  latency as we wait less for the sram to be filled before stream any data out.
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
library work;
use work.Common.all;

-- Component name convention Name_{log2(Samples)}_{log2(NumOfBits)}
entity main_mul8 is
generic 
(
    constant SAMPLES_LOG2: integer;
-- The value of the prime we are working, it use to perform proper padding.	
	constant P_VALUE: integer := 503
);
port
(
    Clk: in std_logic;
    Rst_n: in std_logic;
    start_in: in std_logic;
-- One when all the config internal IPs are done.   
-- The data is present next clock cycle. 
    config_done: out std_logic;

    a_data: in std_logic;
    b_data: in std_logic;
    last_frame: in std_logic;
    -- data_in_rdy: in std_logic;
    
 -- Momentetly we suppose tha the tb always sync the data in.   
    a_data_rdy: in std_logic  := '0';
    a_data_last: in std_logic  := '0';
    b_data_rdy: in std_logic := '0';
    b_data_last: in std_logic := '0';
    data_in_rdy: in std_logic := '0';

    data_out: out std_logic;
    data_out_int: out std_logic_vector((3+SAMPLES_LOG2)-1 downto 0) :=
            (others => '0');
    
    data_out_valid: out std_logic;
    data_out_last: out std_logic;
    
    done: out std_logic
    
-- TODO: RAM Interface, so we would pu the ram insatnce in
-- the tb and have different version if we wanna the synt design.
-- For now I use my ram that do not use the IP block ram so I use
-- the signal inside the entity. This will be changed before ship.
--   sram_rw, sram_ce: in std_logic; 
--   sram_data_in: out std_logic_vector(127 downto 0);
--   sram_data_out: in std_logic_vector(127 downto 0)
);
end main_mul8;

architecture Behavioral of main_mul8 is
    
-- Main COmponent FSM
    component FSM is
    port
    ( 
        Clk : in STD_LOGIC; Rst_n : in STD_LOGIC;
    -- Global Circuit inputs   
        start_in:              in std_logic;
        data_in_rdy:           in std_logic;
        last_frame_reg:        in std_logic;
    -- FSM INPIUTS FROM DP
        dp_cnt_tc:             in std_logic;
        dp_xfft_a_config_tready:  in std_logic;
        dp_xfft_b_config_tready:  in std_logic;
        dp_cmpy_out_tlast:      in std_logic;
        dp_cmpy_out_tvalid:     in std_logic;   
        dp_ifft_in_tready:        in std_logic;
        dp_ifft_out_tlast:      in std_logic;
        dp_ifft_out_tvalid:     in std_logic;
        dp_ifft_config_tready:    in std_logic;
    -- FSM Outputs to DP   
        fsm_ip_rst:                out std_logic;   
        fsm_xfft_in_tvalid:     out std_logic;
        fsm_xfft_out_tready:    out std_logic;
        fsm_xfft_config_tvalid: out std_logic;
        fsm_ifft_in_tlast:      out std_logic;  
        fsm_ifft_in_tvalid:     out std_logic; 
        fsm_ifft_out_tready:   out std_logic;
        fsm_ifft_config_tvalid: out std_logic;
        fsm_cnt_en: out std_logic;
        fsm_cnt_rst: out std_logic;    
        fsm_xfft_config_data_sel: out std_logic;      
        fsm_sram_we: out std_logic;                        
        fsm_sram_re: out std_logic;      
        fsm_sram_CSn: out std_logic;                   
        fsm_sram_rst_fsm: out std_logic; 
        fsm_sram_addr_sel: out std_logic_vector(1 downto 0);                      
        fsm_sram_data_sel: out std_logic; 
    -- Global Outputs    
        done: out std_logic;
        out_en: out std_logic;
        config_done:   out std_logic;
        data_out_last: out std_logic;
        data_out_valid: out std_logic;		
-- When one  indicate that the system is used in extended mode such that padded hase been added at the input,
-- The transform is done on 2N but the output data is only in the 1:N samples, so we stop the FSM before reaching the 
-- 2**(2N) terminal count. In the case that the fsm_cnt reached p, than dp_cnt_pad_tc is 1
		is_extended: in std_logic := '0';
		dp_cnt_pad_tc: in std_logic := '0'
    );
    end component;
    
    component DP_8 is
    generic (constant P_VALUE: integer; 
    constant SAMPLES_LOG2: integer); 
    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;
               
        fsm_ip_rst:             in std_logic;   
        fsm_xfft_in_tvalid:     in std_logic;
        fsm_xfft_out_tready:    in std_logic;
        fsm_xfft_config_tvalid: in std_logic;
        fsm_ifft_in_tlast:      in std_logic;  
        fsm_ifft_in_tvalid:     in std_logic; 
        fsm_ifft_out_tready:    in std_logic;
        fsm_ifft_config_tvalid: in std_logic;
        fsm_cnt_en:  in std_logic;
        fsm_cnt_rst: in std_logic;    
        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; 
        fsm_out_en: in std_logic;
        fsm_use_ifft_sram: in std_logic;
        
        dp_cnt_tc:             out std_logic;
		dp_cnt_pad_tc:         out std_logic;
        dp_xfft_a_config_tready:  out std_logic;
        dp_xfft_b_config_tready:  out std_logic;
        dp_cmpy_out_tlast:      out std_logic;
        dp_cmpy_out_tvalid:     out std_logic;
        dp_ifft_in_tready:      out std_logic;
        dp_ifft_out_tlast:      out std_logic;
        dp_ifft_out_tvalid:     out std_logic;
        dp_ifft_config_tready:  out std_logic;
        
-- DP Output:        
        dp_out_bin: out std_logic;
        dp_out_int: out std_logic_vector((3+SAMPLES_LOG2)-1 downto 0) := (others => '0')
    );
    end component;
     
    component RegN is
    generic (N: integer := 16);
    port
    (
        CLK:     in     std_logic;
        Rst_n:   in     std_logic;
        En:      in     std_logic;
        Clr:      in std_logic := '0';
        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;
        Clr:      in std_logic := '0';
        D:        in     std_logic;
        Q:        out std_logic
    );
    end component;
    
--- Signals
    signal last_frame_reg: std_logic;
    signal a_data_reg: std_logic;    
    signal b_data_reg: std_logic;     
    
    
-- FSM Signals
    signal fsm_done:                 std_logic;
    signal fsm_ip_rst:               std_logic;               
    signal fsm_out_en:               std_logic; 
    signal fsm_cnt_en:               std_logic;
    signal fsm_sram_re:              std_logic;                 
    signal fsm_cnt_rst:              std_logic;                   
    signal fsm_sram_we:              std_logic; 
    signal fsm_sram_CSn:             std_logic; 
    signal fsm_config_done:          std_logic;                  
    signal fsm_sram_rst_fsm:         std_logic; 
    signal fsm_data_out_last:        std_logic;             
    signal fsm_sram_data_sel:        std_logic; 
    signal fsm_ifft_in_tlast:        std_logic; 
    signal fsm_use_ifft_sram:        std_logic; 
    signal fsm_sram_addr_sel:        adr_sel; 
    signal fsm_ifft_in_tvalid:       std_logic; 
    signal fsm_xfft_in_tvalid:       std_logic; 
    signal fsm_data_out_valid:       std_logic;
    signal fsm_ifft_out_tready:      std_logic;
    signal fsm_xfft_out_tready:      std_logic;   
    signal fsm_xfft_config_tvalid:   std_logic;  
    signal fsm_ifft_config_tvalid:   std_logic;      

-- DP Out Signals      
    signal dp_cnt_tc:                std_logic; 
	signal dp_cnt_pad_tc:            std_logic;
    signal dp_bin_out:               std_logic;                              
    signal dp_cmpy_out_tlast:        std_logic;              
    signal dp_cmpy_out_tvalid:       std_logic;             
    signal dp_ifft_in_tready:        std_logic;              
    signal dp_ifft_out_tlast:        std_logic;              
    signal dp_ifft_out_tvalid:       std_logic;             
    signal dp_ifft_config_tready:    std_logic;              
    signal dp_xfft_a_config_tready:  std_logic;       
    signal dp_xfft_b_config_tready:  std_logic;    
         
begin

-- Input registers
A_InReg: Reg1  port map (
    Clk => Clk, Rst_n => Rst_n, En => data_in_rdy,
    D => a_data, Q => a_data_reg
);

B_InReg: Reg1 port map (
    Clk => Clk, Rst_n => Rst_n, En => data_in_rdy,
    D => b_data, Q => b_data_reg
);

LastFrameInReg: Reg1 port map (
    Clk => Clk, Rst_n => Rst_n, En => '1',
    D => last_frame, Q => last_frame_reg
);

-- DP_Comp: DP_14_ext_3 generic map
DP_Comp: DP_8 generic map
(
    P_VALUE => P_VALUE, 
    SAMPLES_LOG2 => SAMPLES_LOG2
) port map (
    Clk => Clk, Rst_n => Rst_n,
-- DP Data Inputs    
    a_data_bin => a_data_reg, 
    b_data_bin => b_data_reg,  
    last_frame_reg => last_frame_reg,
-- DP Output
    dp_out_bin              => data_out,
--    dp_out_int              => data_out_int,       
-- DP FSM Input Inputs    
    fsm_ip_rst              => fsm_ip_rst, 
    fsm_xfft_in_tvalid      => fsm_xfft_in_tvalid,
    fsm_xfft_out_tready     => fsm_xfft_out_tready,
    fsm_xfft_config_tvalid  => fsm_xfft_config_tvalid,
    fsm_ifft_in_tlast       => fsm_ifft_in_tlast,  
    fsm_ifft_in_tvalid      => fsm_ifft_in_tvalid, 
    fsm_ifft_out_tready     => fsm_ifft_out_tready,
    fsm_ifft_config_tvalid  => fsm_ifft_config_tvalid,
    fsm_cnt_en              => fsm_cnt_en,
    fsm_cnt_rst             => fsm_cnt_rst,    
    fsm_sram_we             => fsm_sram_we,                        
    fsm_sram_re             => fsm_sram_re,    
    fsm_sram_CSn            => fsm_sram_CSn,                
    fsm_sram_rst            => fsm_sram_rst_fsm,
    fsm_sram_addr_sel       => fsm_sram_addr_sel,                       
    fsm_sram_data_sel       => fsm_sram_data_sel, 
    fsm_out_en              => fsm_out_en,
    fsm_use_ifft_sram       => fsm_use_ifft_sram,
    
-- DP generated Signals        
    dp_cnt_tc               => dp_cnt_tc,  
	dp_cnt_pad_tc           => dp_cnt_pad_tc,  
    dp_xfft_a_config_tready => dp_xfft_a_config_tready,
    dp_xfft_b_config_tready => dp_xfft_b_config_tready,
    dp_cmpy_out_tlast       => dp_cmpy_out_tlast,
    dp_cmpy_out_tvalid      => dp_cmpy_out_tvalid,
    dp_ifft_in_tready       => dp_ifft_in_tready,
    dp_ifft_out_tlast       => dp_ifft_out_tlast,
    dp_ifft_out_tvalid      => dp_ifft_out_tvalid,
    dp_ifft_config_tready   => dp_ifft_config_tready
);

FSM_Control: FSM port map (
    Clk => Clk, Rst_n => Rst_n,

    -- INPUTS   
    start_in => start_in,
    data_in_rdy => data_in_rdy, last_frame_reg => last_frame_reg, dp_cnt_tc => dp_cnt_tc,  
    dp_cmpy_out_tlast  => dp_cmpy_out_tlast, 
    dp_cmpy_out_tvalid => dp_cmpy_out_tvalid, 
    
    dp_ifft_in_tready => dp_ifft_in_tready, 
    dp_xfft_a_config_tready => dp_xfft_a_config_tready, 
    dp_xfft_b_config_tready => dp_xfft_b_config_tready,
    
    dp_ifft_out_tlast => dp_ifft_out_tlast, 
    dp_ifft_out_tvalid => dp_ifft_out_tvalid, 
    dp_ifft_config_tready => dp_ifft_config_tready,

    -- OUTPUTS    
    fsm_ip_rst => fsm_ip_rst,
    fsm_xfft_in_tvalid => fsm_xfft_in_tvalid, fsm_xfft_out_tready => fsm_xfft_out_tready, fsm_xfft_config_tvalid => fsm_xfft_config_tvalid,
    fsm_ifft_in_tlast =>  fsm_ifft_in_tlast,  fsm_ifft_in_tvalid  => fsm_ifft_in_tvalid,  fsm_ifft_out_tready    => fsm_ifft_out_tready, 
    fsm_ifft_config_tvalid => fsm_ifft_config_tvalid, 

    -- Counter out Signals
    fsm_cnt_rst => fsm_cnt_rst, fsm_cnt_en => fsm_cnt_en,   

    -- SRAM OUTPUTS
    fsm_sram_we => fsm_sram_we, fsm_sram_re => fsm_sram_re, fsm_sram_CSn => fsm_sram_CSn,
    fsm_sram_rst_fsm => fsm_sram_rst_fsm, fsm_sram_addr_sel => fsm_sram_addr_sel, 
    fsm_sram_data_sel => fsm_sram_data_sel,
    data_out_valid => fsm_data_out_valid,
        
    -- General Signals
    done => fsm_done, out_en => fsm_out_en, config_done => fsm_config_done,
    data_out_last => fsm_data_out_last, 
	
-- Padded sequence.
	is_extended => '1',
	dp_cnt_pad_tc => dp_cnt_pad_tc 
);

--TODO: I probably woould like to add a register to all of this three signals eventually.....
done <= fsm_done;
config_done <= fsm_config_done;
data_out_last  <= fsm_data_out_last;
data_out_valid <= fsm_data_out_valid;


-- We need to delay out_last_frame.

end Behavioral;
