OpenCores
URL https://opencores.org/ocsvn/astron_wb_fft/astron_wb_fft/trunk

Subversion Repositories astron_wb_fft

[/] [astron_wb_fft/] [trunk/] [fft_r2_wide.vhd] - Rev 5

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------------
--
-- Copyright 2020
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
-- 
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
-- 
--     http://www.apache.org/licenses/LICENSE-2.0
-- 
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
--------------------------------------------------------------------------------
-- Purpose: The fft_r2_wide unit performs a complex FFT that is partly pipelined 
--          and partly parallel. 
--
-- Description:
--  The fft_r2_wide supports:
--
--  * Complex input
--    For complex input use_separate = false.
--
--    When use_reorder=true then the output bins of the FFT are re-ordered to 
--    undo the bit-reversed (or bit-flipped) default radix 2 FFT output order.
--    The fft_r2_wide then outputs first 0 Hz and the positive frequencies
--    and then the negative frequencies. The use_reorder is performed at both
--    the pipelined stage and the parallel stage.
--
--    When use_fft_shift=true then the fft_r2_wide then outputs the frequency
--    bins in incrementing order, so first the negative frequencies, then 0 Hz
--    and then the positive frequencies.
--    When use_fft_shift = true then also use_reorder must be true.
--
--  * Two real inputs:
--    When use_separate=true then the fft_r2_wide can be used to process two
--    real streams. The first real stream (A) presented on the real input, the
--    second real stream (B) presented on the imaginary input. The separation
--    unit outputs the spectrum of A and B in an alternating way.
--    When use_separate = true then also use_reorder must be true.
--    When use_separate = true then the use_fft_shift must be false, because
--    fft_shift() only applies to spectra for complex input.
--
-- Remarks:
-- . This fft_r2_wide also support wb_factor = 1 (= only a fft_r2_pipe
--   instance) or wb_factor = g_fft.nof_points (= only a fft_r2_par instance).
--   Care must be taken to properly account for guard_w and out_gain_w,
--   therefore it is best to simply use a structural approach that generates
--   seperate instances for each case:
--   . wb_factor = 1                                  --> pipe
--   . wb_factor > 1 AND wb_factor < g_fft.nof_points --> wide
--   . wb_factor = g_fft.nof_points                   --> par
-- . This fft_r2_wide uses the use_reorder in the pipeline FFT, in the parallel
--   FFT and also has reorder memory in the fft_sepa_wide instance. The reorder
--   memories in the FFTs can maybe be saved by using only the reorder memory
--   in the fft_sepa_wide instance. This would require changing the indexing in
--   fft_sepa_wide instance.
-- . The reorder memory in the pipeline FFT, parallel FFT and in the
--   fft_sepa_wide could make reuse of a reorder component from the reorder
--   library instead of using a dedicated local solution.
 
library ieee, common_pkg_lib, common_components_lib, astron_requantize_lib, astron_r2sdf_fft_lib;
use IEEE.std_logic_1164.all;
use common_pkg_lib.common_pkg.all;
use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
use work.fft_pkg.all; 
 
entity fft_r2_wide is
  generic (
    g_fft          : t_fft := c_fft;                   -- generics for the FFT
    g_pft_pipeline : t_fft_pipeline := c_fft_pipeline; -- For the pipelined part, from astron_r2sdf_fft_lib.rTwoSDFPkg
    g_fft_pipeline : t_fft_pipeline := c_fft_pipeline  -- For the parallel part, from astron_r2sdf_fft_lib.rTwoSDFPkg
  );
  port (
    clk        : in  std_logic;
    rst        : in  std_logic := '0';
    in_re_arr  : in  t_fft_slv_arr(g_fft.wb_factor-1 downto 0); -- = time samples t3, t2, t1, t0
    in_im_arr  : in  t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
    in_val     : in  std_logic := '1';
    out_re_arr : out t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
    out_im_arr : out t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
    out_val    : out std_logic
  );
end entity fft_r2_wide;
 
architecture rtl of fft_r2_wide is
 
  type t_fft_arr is array(integer range <> ) of t_fft;  -- An array of t_fft's generics. 
 
  ----------------------------------------------------------
  -- This function creates an array of t_fft generics 
  -- for the pipelined fft's of the first stage.The array is 
  -- based on the g_fft generic that belongs to the 
  -- fft_r2_wide entity. 
  -- Most imortant in the settings are twiddle_offset and 
  -- the nof_points.
  ----------------------------------------------------------
  function func_create_generic_for_pipe_fft(input : t_fft) return t_fft_arr is
    variable v_nof_points : natural := input.nof_points/input.wb_factor;                 -- The nof_points for the pipelined fft stages
    variable v_return     : t_fft_arr(input.wb_factor-1 downto 0) := (others => input);  -- Variable that holds the return values
  begin
    for I in 0 to input.wb_factor-1 loop
      v_return(I).use_reorder    := input.use_reorder; -- Pass on use_reorder
      v_return(I).use_fft_shift  := false;             -- FFT shift function is forced to false
      v_return(I).use_separate   := false;             -- Separate function is forced to false. 
      v_return(I).twiddle_offset := I;                 -- Twiddle offset is set to the order number of the pipelined fft. 
      v_return(I).nof_points     := v_nof_points;      -- Set the nof points 
      v_return(I).in_dat_w       := input.stage_dat_w; -- Set the input width  
      v_return(I).out_dat_w      := input.stage_dat_w; -- Set the output width. 
      v_return(I).out_gain_w     := 0;                 -- Output gain is forced to 0
      v_return(I).guard_w        := 0;                 -- Set the guard_w to 0 to enable scaling at every stage. 
      v_return(I).guard_enable   := false;             -- No input guard. 
    end loop;                               
    return v_return; 
  end;
 
  ----------------------------------------------------------
  -- This function creates t_fft generic for the 
  -- parallel fft stage, based on the g_fft generic that 
  -- belongs to the fft_r2_wide entity. 
  ----------------------------------------------------------
  function func_create_generic_for_par_fft(input : t_fft) return t_fft is
    variable v_return         : t_fft   := input;  -- Variable that holds the return value
  begin                                     
      v_return.use_reorder    := input.use_reorder;    -- Pass on use_reorder
      v_return.use_fft_shift  := input.use_fft_shift;  -- Pass on use_fft_shift
      v_return.use_separate   := false;                -- Separate function is forced to false, because it is handled outside the parallel fft
      v_return.twiddle_offset := 0;                    -- Twiddle offset is forced to 0, which is also the input.twiddle_offset default
      v_return.nof_points     := input.wb_factor;      -- Set the number of points to wb_factor
      v_return.in_dat_w       := input.stage_dat_w;    -- Specify the input width
      v_return.out_dat_w      := input.stage_dat_w;    -- Output width 
      v_return.out_gain_w     := 0;                    -- Output gain is forced to 0, because it is handled outside the parallel fft
      v_return.guard_w        := input.guard_w;        -- Set the guard_w here to skip the scaling on the last stages
      v_return.guard_enable   := false;                -- No input guard. 
    return v_return; 
  end;
 
  constant c_pipeline_remove_lsb : natural := 0;
 
  constant c_fft_r2_pipe_arr  : t_fft_arr(g_fft.wb_factor-1 downto 0) := func_create_generic_for_pipe_fft(g_fft); 
  constant c_fft_r2_par       : t_fft                                 := func_create_generic_for_par_fft(g_fft);
 
  constant c_in_scale_w       : natural := g_fft.stage_dat_w - g_fft.in_dat_w - sel_a_b(g_fft.guard_enable, g_fft.guard_w, 0);              
 
  constant c_out_scale_w      : integer := c_fft_r2_par.out_dat_w - g_fft.out_dat_w - g_fft.out_gain_w;  -- Estimate number of LSBs to throw away when > 0 or insert when < 0
 
  signal in_fft_pipe_re_arr   : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
  signal in_fft_pipe_im_arr   : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
 
  signal out_fft_pipe_re_arr  : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
  signal out_fft_pipe_im_arr  : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
 
  signal in_fft_par_re_arr    : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
  signal in_fft_par_im_arr    : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
 
  signal fft_pipe_out_re      : std_logic_vector(g_fft.out_dat_w-1 downto 0);
  signal fft_pipe_out_im      : std_logic_vector(g_fft.out_dat_w-1 downto 0);
 
  signal fft_out_re_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
  signal fft_out_im_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
  signal fft_out_val          : std_logic;                                   
 
  signal sep_out_re_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);   
  signal sep_out_im_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);   
  signal sep_out_val          : std_logic;                                   
 
  signal int_val              : std_logic_vector(g_fft.wb_factor-1 downto 0);
 
  signal out_cplx             : std_logic_vector(c_nof_complex*g_fft.stage_dat_w-1 downto 0);
  signal in_cplx              : std_logic_vector(c_nof_complex*g_fft.stage_dat_w-1 downto 0);
 
begin
 
  -- Default to fft_r2_pipe when g_fft.wb_factor=1
  gen_fft_r2_pipe : if g_fft.wb_factor=1 generate
    u_fft_r2_pipe : entity work.fft_r2_pipe
    generic map (
      g_fft      => g_fft,
      g_pipeline => g_pft_pipeline
    )
    port map (
      clk        => clk,
      rst        => rst,
      in_re      => in_re_arr(0)(g_fft.in_dat_w-1 downto 0),
      in_im      => in_im_arr(0)(g_fft.in_dat_w-1 downto 0),
      in_val     => in_val,
      out_re     => fft_pipe_out_re,
      out_im     => fft_pipe_out_im,
      out_val    => out_val
    );
 
    out_re_arr(0) <= resize_fft_svec(fft_pipe_out_re);
    out_im_arr(0) <= resize_fft_svec(fft_pipe_out_im);
  end generate;
 
  -- Default to fft_r2_par when g_fft.wb_factor=g_fft.nof_points
  gen_fft_r2_par : if g_fft.wb_factor=g_fft.nof_points generate
    u_fft_r2_par : entity work.fft_r2_par
    generic map (
      g_fft      => g_fft,
      g_pipeline => g_fft_pipeline
    )
    port map (
      clk        => clk,
      rst        => rst,
      in_re_arr  => in_re_arr,
      in_im_arr  => in_im_arr,
      in_val     => in_val,
      out_re_arr => out_re_arr,
      out_im_arr => out_im_arr,
      out_val    => out_val
    );
  end generate;
 
  -- Create wideband FFT as combinination of g_fft.wb_factor instances of fft_r2_pipe with one instance of fft_r2_par
  gen_fft_r2_wide : if g_fft.wb_factor>1 and g_fft.wb_factor<g_fft.nof_points generate
 
    ---------------------------------------------------------------
    -- PIPELINED FFT STAGE
    ---------------------------------------------------------------
 
    -- Inputs are prepared/scaled for the pipelined ffts
    gen_fft_pipe_inputs : for I in 0 to g_fft.wb_factor-1 generate
      in_fft_pipe_re_arr(I) <= scale_and_resize_svec(in_re_arr(I), c_in_scale_w, c_fft_slv_w);
      in_fft_pipe_im_arr(I) <= scale_and_resize_svec(in_im_arr(I), c_in_scale_w, c_fft_slv_w);
    end generate;   
 
    -- The first stage of the wideband fft consist of the generation of g_fft.wb_factor
    -- pipelined fft's. These pipelines fft's operate in parallel.   
    gen_pipelined_ffts : for I in g_fft.wb_factor-1 downto 0 generate
      u_pft : entity work.fft_r2_pipe
      generic map (
        g_fft      => c_fft_r2_pipe_arr(I),   -- generics for the pipelined FFTs
        g_pipeline => g_pft_pipeline          -- pipeline generics for the pipelined FFTs
      )
      port map (
        clk       => clk,
        rst       => rst,
        in_re     => in_fft_pipe_re_arr(I)(c_fft_r2_pipe_arr(I).in_dat_w-1 downto 0),
        in_im     => in_fft_pipe_im_arr(I)(c_fft_r2_pipe_arr(I).in_dat_w-1 downto 0),
        in_val    => in_val,
        out_re    => out_fft_pipe_re_arr(I)(c_fft_r2_pipe_arr(I).out_dat_w-1 downto 0),
        out_im    => out_fft_pipe_im_arr(I)(c_fft_r2_pipe_arr(I).out_dat_w-1 downto 0),
        out_val   => int_val(I)
      );     
    end generate;       
 
 
    ---------------------------------------------------------------
    -- PARALLEL FFT STAGE
    ---------------------------------------------------------------
 
    -- Create input for parallel FFT
    gen_inputs_for_par : for I in g_fft.wb_factor-1 downto 0 generate
      in_fft_par_re_arr(I) <= resize_fft_svec(out_fft_pipe_re_arr(I)(c_fft_r2_pipe_arr(I).out_dat_w-1 downto 0));
      in_fft_par_im_arr(I) <= resize_fft_svec(out_fft_pipe_im_arr(I)(c_fft_r2_pipe_arr(I).out_dat_w-1 downto 0));
    end generate;
 
    -- The g_fft.wb_factor outputs of the pipelined fft's are offered
    -- to the input of a single parallel FFT. 
    u_fft : entity work.fft_r2_par
    generic map (
      g_fft      => c_fft_r2_par,           -- generics for the FFT
      g_pipeline => g_fft_pipeline          -- pipeline generics for the parallel FFT
    )
    port map (
      clk        => clk,
      rst        => rst,
      in_re_arr  => in_fft_par_re_arr,
      in_im_arr  => in_fft_par_im_arr,
      in_val     => int_val(0),
      out_re_arr => fft_out_re_arr,
      out_im_arr => fft_out_im_arr,
      out_val    => fft_out_val
    );
 
    ---------------------------------------------------------------
    -- OPTIONAL: SEPARATION STAGE
    ---------------------------------------------------------------
    -- When the separate functionality is required:
    gen_separate : if g_fft.use_separate generate 
      u_separator : entity work.fft_sepa_wide
      generic map (
        g_fft      => g_fft
      )
      port map (
        clk        => clk,
        rst        => rst,
        in_re_arr  => fft_out_re_arr, 
        in_im_arr  => fft_out_im_arr, 
        in_val     => fft_out_val,     
        out_re_arr => sep_out_re_arr, 
        out_im_arr => sep_out_im_arr, 
        out_val    => sep_out_val     
      );
    end generate;
 
     -- In case no separtion is required, the output of the parallel fft is used. 
    no_separate : if g_fft.use_separate=false generate 
      sep_out_re_arr <= fft_out_re_arr;    
      sep_out_im_arr <= fft_out_im_arr;    
      sep_out_val    <= fft_out_val;
    end generate;  
 
    ---------------------------------------------------------------
    -- OUTPUT QUANTIZER
    ---------------------------------------------------------------
    gen_output_requantizers : for I in g_fft.wb_factor-1 downto 0 generate
      u_requantize_output_re : entity astron_requantize_lib.common_requantize
      generic map (
        g_representation      => "SIGNED",      
        g_lsb_w               => c_out_scale_w,               
        g_lsb_round           => TRUE,           
        g_lsb_round_clip      => FALSE,      
        g_msb_clip            => FALSE,            
        g_msb_clip_symmetric  => FALSE,  
        g_pipeline_remove_lsb => c_pipeline_remove_lsb, 
        g_pipeline_remove_msb => 0, 
        g_in_dat_w            => g_fft.stage_dat_w,            
        g_out_dat_w           => g_fft.out_dat_w
      )
      port map (
        clk        => clk,
        in_dat     => sep_out_re_arr(I),
        out_dat    => out_re_arr(I), 
        out_ovr    => open
      );  
 
      u_requantize_output_im : entity astron_requantize_lib.common_requantize
      generic map (
        g_representation      => "SIGNED",      
        g_lsb_w               => c_out_scale_w,               
        g_lsb_round           => TRUE,           
        g_lsb_round_clip      => FALSE,      
        g_msb_clip            => FALSE,            
        g_msb_clip_symmetric  => FALSE,  
        g_pipeline_remove_lsb => c_pipeline_remove_lsb, 
        g_pipeline_remove_msb => 0, 
        g_in_dat_w            => g_fft.stage_dat_w,            
        g_out_dat_w           => g_fft.out_dat_w
      )
      port map (
        clk        => clk,
        in_dat     => sep_out_im_arr(I),
        out_dat    => out_im_arr(I), 
        out_ovr    => open
      );  
    end generate;     
 
    u_out_val : entity common_components_lib.common_pipeline_sl
    generic map (
      g_pipeline => c_pipeline_remove_lsb
    )
    port map (
      rst     => rst,
      clk     => clk,
      in_dat  => sep_out_val,
      out_dat => out_val
    );
 
  end generate;  
end rtl;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.