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] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 danv
--------------------------------------------------------------------------------
2
--
3 3 danv
-- Copyright 2020
4 2 danv
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
5
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
6 3 danv
-- 
7
-- Licensed under the Apache License, Version 2.0 (the "License");
8
-- you may not use this file except in compliance with the License.
9
-- You may obtain a copy of the License at
10
-- 
11
--     http://www.apache.org/licenses/LICENSE-2.0
12
-- 
13
-- Unless required by applicable law or agreed to in writing, software
14
-- distributed under the License is distributed on an "AS IS" BASIS,
15
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
-- See the License for the specific language governing permissions and
17
-- limitations under the License.
18 2 danv
--
19
--------------------------------------------------------------------------------
20
-- Purpose: The fft_r2_wide unit performs a complex FFT that is partly pipelined 
21
--          and partly parallel. 
22
--
23
-- Description:
24
--  The fft_r2_wide supports:
25
--
26
--  * Complex input
27
--    For complex input use_separate = false.
28
--
29
--    When use_reorder=true then the output bins of the FFT are re-ordered to 
30
--    undo the bit-reversed (or bit-flipped) default radix 2 FFT output order.
31
--    The fft_r2_wide then outputs first 0 Hz and the positive frequencies
32
--    and then the negative frequencies. The use_reorder is performed at both
33
--    the pipelined stage and the parallel stage.
34
--
35
--    When use_fft_shift=true then the fft_r2_wide then outputs the frequency
36
--    bins in incrementing order, so first the negative frequencies, then 0 Hz
37
--    and then the positive frequencies.
38
--    When use_fft_shift = true then also use_reorder must be true.
39
--
40
--  * Two real inputs:
41
--    When use_separate=true then the fft_r2_wide can be used to process two
42
--    real streams. The first real stream (A) presented on the real input, the
43
--    second real stream (B) presented on the imaginary input. The separation
44
--    unit outputs the spectrum of A and B in an alternating way.
45
--    When use_separate = true then also use_reorder must be true.
46
--    When use_separate = true then the use_fft_shift must be false, because
47
--    fft_shift() only applies to spectra for complex input.
48
--
49
-- Remarks:
50
-- . This fft_r2_wide also support wb_factor = 1 (= only a fft_r2_pipe
51
--   instance) or wb_factor = g_fft.nof_points (= only a fft_r2_par instance).
52
--   Care must be taken to properly account for guard_w and out_gain_w,
53
--   therefore it is best to simply use a structural approach that generates
54
--   seperate instances for each case:
55
--   . wb_factor = 1                                  --> pipe
56
--   . wb_factor > 1 AND wb_factor < g_fft.nof_points --> wide
57
--   . wb_factor = g_fft.nof_points                   --> par
58
-- . This fft_r2_wide uses the use_reorder in the pipeline FFT, in the parallel
59
--   FFT and also has reorder memory in the fft_sepa_wide instance. The reorder
60
--   memories in the FFTs can maybe be saved by using only the reorder memory
61
--   in the fft_sepa_wide instance. This would require changing the indexing in
62
--   fft_sepa_wide instance.
63
-- . The reorder memory in the pipeline FFT, parallel FFT and in the
64
--   fft_sepa_wide could make reuse of a reorder component from the reorder
65
--   library instead of using a dedicated local solution.
66
 
67 5 danv
library ieee, common_pkg_lib, common_components_lib, astron_requantize_lib, astron_r2sdf_fft_lib;
68 2 danv
use IEEE.std_logic_1164.all;
69
use common_pkg_lib.common_pkg.all;
70 5 danv
use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
71 2 danv
use work.fft_pkg.all;
72
 
73
entity fft_r2_wide is
74
  generic (
75
    g_fft          : t_fft := c_fft;                   -- generics for the FFT
76 5 danv
    g_pft_pipeline : t_fft_pipeline := c_fft_pipeline; -- For the pipelined part, from astron_r2sdf_fft_lib.rTwoSDFPkg
77
    g_fft_pipeline : t_fft_pipeline := c_fft_pipeline  -- For the parallel part, from astron_r2sdf_fft_lib.rTwoSDFPkg
78 2 danv
  );
79
  port (
80
    clk        : in  std_logic;
81
    rst        : in  std_logic := '0';
82
    in_re_arr  : in  t_fft_slv_arr(g_fft.wb_factor-1 downto 0); -- = time samples t3, t2, t1, t0
83
    in_im_arr  : in  t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
84
    in_val     : in  std_logic := '1';
85
    out_re_arr : out t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
86
    out_im_arr : out t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
87
    out_val    : out std_logic
88
  );
89
end entity fft_r2_wide;
90
 
91
architecture rtl of fft_r2_wide is
92
 
93
  type t_fft_arr is array(integer range <> ) of t_fft;  -- An array of t_fft's generics. 
94
 
95
  ----------------------------------------------------------
96
  -- This function creates an array of t_fft generics 
97
  -- for the pipelined fft's of the first stage.The array is 
98
  -- based on the g_fft generic that belongs to the 
99
  -- fft_r2_wide entity. 
100
  -- Most imortant in the settings are twiddle_offset and 
101
  -- the nof_points.
102
  ----------------------------------------------------------
103
  function func_create_generic_for_pipe_fft(input : t_fft) return t_fft_arr is
104
    variable v_nof_points : natural := input.nof_points/input.wb_factor;                 -- The nof_points for the pipelined fft stages
105
    variable v_return     : t_fft_arr(input.wb_factor-1 downto 0) := (others => input);  -- Variable that holds the return values
106
  begin
107
    for I in 0 to input.wb_factor-1 loop
108
      v_return(I).use_reorder    := input.use_reorder; -- Pass on use_reorder
109
      v_return(I).use_fft_shift  := false;             -- FFT shift function is forced to false
110
      v_return(I).use_separate   := false;             -- Separate function is forced to false. 
111
      v_return(I).twiddle_offset := I;                 -- Twiddle offset is set to the order number of the pipelined fft. 
112
      v_return(I).nof_points     := v_nof_points;      -- Set the nof points 
113
      v_return(I).in_dat_w       := input.stage_dat_w; -- Set the input width  
114
      v_return(I).out_dat_w      := input.stage_dat_w; -- Set the output width. 
115
      v_return(I).out_gain_w     := 0;                 -- Output gain is forced to 0
116
      v_return(I).guard_w        := 0;                 -- Set the guard_w to 0 to enable scaling at every stage. 
117
      v_return(I).guard_enable   := false;             -- No input guard. 
118
    end loop;
119
    return v_return;
120
  end;
121
 
122
  ----------------------------------------------------------
123
  -- This function creates t_fft generic for the 
124
  -- parallel fft stage, based on the g_fft generic that 
125
  -- belongs to the fft_r2_wide entity. 
126
  ----------------------------------------------------------
127
  function func_create_generic_for_par_fft(input : t_fft) return t_fft is
128
    variable v_return         : t_fft   := input;  -- Variable that holds the return value
129
  begin
130
      v_return.use_reorder    := input.use_reorder;    -- Pass on use_reorder
131
      v_return.use_fft_shift  := input.use_fft_shift;  -- Pass on use_fft_shift
132
      v_return.use_separate   := false;                -- Separate function is forced to false, because it is handled outside the parallel fft
133
      v_return.twiddle_offset := 0;                    -- Twiddle offset is forced to 0, which is also the input.twiddle_offset default
134
      v_return.nof_points     := input.wb_factor;      -- Set the number of points to wb_factor
135
      v_return.in_dat_w       := input.stage_dat_w;    -- Specify the input width
136
      v_return.out_dat_w      := input.stage_dat_w;    -- Output width 
137
      v_return.out_gain_w     := 0;                    -- Output gain is forced to 0, because it is handled outside the parallel fft
138
      v_return.guard_w        := input.guard_w;        -- Set the guard_w here to skip the scaling on the last stages
139
      v_return.guard_enable   := false;                -- No input guard. 
140
    return v_return;
141
  end;
142
 
143
  constant c_pipeline_remove_lsb : natural := 0;
144
 
145
  constant c_fft_r2_pipe_arr  : t_fft_arr(g_fft.wb_factor-1 downto 0) := func_create_generic_for_pipe_fft(g_fft);
146
  constant c_fft_r2_par       : t_fft                                 := func_create_generic_for_par_fft(g_fft);
147
 
148
  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);
149
 
150
  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
151
 
152
  signal in_fft_pipe_re_arr   : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
153
  signal in_fft_pipe_im_arr   : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
154
 
155
  signal out_fft_pipe_re_arr  : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
156
  signal out_fft_pipe_im_arr  : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
157
 
158
  signal in_fft_par_re_arr    : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
159
  signal in_fft_par_im_arr    : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
160
 
161
  signal fft_pipe_out_re      : std_logic_vector(g_fft.out_dat_w-1 downto 0);
162
  signal fft_pipe_out_im      : std_logic_vector(g_fft.out_dat_w-1 downto 0);
163
 
164
  signal fft_out_re_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
165
  signal fft_out_im_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
166
  signal fft_out_val          : std_logic;
167
 
168
  signal sep_out_re_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
169
  signal sep_out_im_arr       : t_fft_slv_arr(g_fft.wb_factor-1 downto 0);
170
  signal sep_out_val          : std_logic;
171
 
172
  signal int_val              : std_logic_vector(g_fft.wb_factor-1 downto 0);
173
 
174
  signal out_cplx             : std_logic_vector(c_nof_complex*g_fft.stage_dat_w-1 downto 0);
175
  signal in_cplx              : std_logic_vector(c_nof_complex*g_fft.stage_dat_w-1 downto 0);
176
 
177
begin
178
 
179
  -- Default to fft_r2_pipe when g_fft.wb_factor=1
180
  gen_fft_r2_pipe : if g_fft.wb_factor=1 generate
181
    u_fft_r2_pipe : entity work.fft_r2_pipe
182
    generic map (
183
      g_fft      => g_fft,
184
      g_pipeline => g_pft_pipeline
185
    )
186
    port map (
187
      clk        => clk,
188
      rst        => rst,
189
      in_re      => in_re_arr(0)(g_fft.in_dat_w-1 downto 0),
190
      in_im      => in_im_arr(0)(g_fft.in_dat_w-1 downto 0),
191
      in_val     => in_val,
192
      out_re     => fft_pipe_out_re,
193
      out_im     => fft_pipe_out_im,
194
      out_val    => out_val
195
    );
196
 
197
    out_re_arr(0) <= resize_fft_svec(fft_pipe_out_re);
198
    out_im_arr(0) <= resize_fft_svec(fft_pipe_out_im);
199
  end generate;
200
 
201
  -- Default to fft_r2_par when g_fft.wb_factor=g_fft.nof_points
202
  gen_fft_r2_par : if g_fft.wb_factor=g_fft.nof_points generate
203
    u_fft_r2_par : entity work.fft_r2_par
204
    generic map (
205
      g_fft      => g_fft,
206
      g_pipeline => g_fft_pipeline
207
    )
208
    port map (
209
      clk        => clk,
210
      rst        => rst,
211
      in_re_arr  => in_re_arr,
212
      in_im_arr  => in_im_arr,
213
      in_val     => in_val,
214
      out_re_arr => out_re_arr,
215
      out_im_arr => out_im_arr,
216
      out_val    => out_val
217
    );
218
  end generate;
219
 
220
  -- Create wideband FFT as combinination of g_fft.wb_factor instances of fft_r2_pipe with one instance of fft_r2_par
221
  gen_fft_r2_wide : if g_fft.wb_factor>1 and g_fft.wb_factor<g_fft.nof_points generate
222
 
223
    ---------------------------------------------------------------
224
    -- PIPELINED FFT STAGE
225
    ---------------------------------------------------------------
226
 
227
    -- Inputs are prepared/scaled for the pipelined ffts
228
    gen_fft_pipe_inputs : for I in 0 to g_fft.wb_factor-1 generate
229
      in_fft_pipe_re_arr(I) <= scale_and_resize_svec(in_re_arr(I), c_in_scale_w, c_fft_slv_w);
230
      in_fft_pipe_im_arr(I) <= scale_and_resize_svec(in_im_arr(I), c_in_scale_w, c_fft_slv_w);
231
    end generate;
232
 
233
    -- The first stage of the wideband fft consist of the generation of g_fft.wb_factor
234
    -- pipelined fft's. These pipelines fft's operate in parallel.   
235
    gen_pipelined_ffts : for I in g_fft.wb_factor-1 downto 0 generate
236
      u_pft : entity work.fft_r2_pipe
237
      generic map (
238
        g_fft      => c_fft_r2_pipe_arr(I),   -- generics for the pipelined FFTs
239
        g_pipeline => g_pft_pipeline          -- pipeline generics for the pipelined FFTs
240
      )
241
      port map (
242
        clk       => clk,
243
        rst       => rst,
244
        in_re     => in_fft_pipe_re_arr(I)(c_fft_r2_pipe_arr(I).in_dat_w-1 downto 0),
245
        in_im     => in_fft_pipe_im_arr(I)(c_fft_r2_pipe_arr(I).in_dat_w-1 downto 0),
246
        in_val    => in_val,
247
        out_re    => out_fft_pipe_re_arr(I)(c_fft_r2_pipe_arr(I).out_dat_w-1 downto 0),
248
        out_im    => out_fft_pipe_im_arr(I)(c_fft_r2_pipe_arr(I).out_dat_w-1 downto 0),
249
        out_val   => int_val(I)
250
      );
251
    end generate;
252
 
253
 
254
    ---------------------------------------------------------------
255
    -- PARALLEL FFT STAGE
256
    ---------------------------------------------------------------
257
 
258
    -- Create input for parallel FFT
259
    gen_inputs_for_par : for I in g_fft.wb_factor-1 downto 0 generate
260
      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));
261
      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));
262
    end generate;
263
 
264
    -- The g_fft.wb_factor outputs of the pipelined fft's are offered
265
    -- to the input of a single parallel FFT. 
266
    u_fft : entity work.fft_r2_par
267
    generic map (
268
      g_fft      => c_fft_r2_par,           -- generics for the FFT
269
      g_pipeline => g_fft_pipeline          -- pipeline generics for the parallel FFT
270
    )
271
    port map (
272
      clk        => clk,
273
      rst        => rst,
274
      in_re_arr  => in_fft_par_re_arr,
275
      in_im_arr  => in_fft_par_im_arr,
276
      in_val     => int_val(0),
277
      out_re_arr => fft_out_re_arr,
278
      out_im_arr => fft_out_im_arr,
279
      out_val    => fft_out_val
280
    );
281
 
282
    ---------------------------------------------------------------
283
    -- OPTIONAL: SEPARATION STAGE
284
    ---------------------------------------------------------------
285
    -- When the separate functionality is required:
286
    gen_separate : if g_fft.use_separate generate
287
      u_separator : entity work.fft_sepa_wide
288
      generic map (
289
        g_fft      => g_fft
290
      )
291
      port map (
292
        clk        => clk,
293
        rst        => rst,
294
        in_re_arr  => fft_out_re_arr,
295
        in_im_arr  => fft_out_im_arr,
296
        in_val     => fft_out_val,
297
        out_re_arr => sep_out_re_arr,
298
        out_im_arr => sep_out_im_arr,
299
        out_val    => sep_out_val
300
      );
301
    end generate;
302
 
303
     -- In case no separtion is required, the output of the parallel fft is used. 
304
    no_separate : if g_fft.use_separate=false generate
305
      sep_out_re_arr <= fft_out_re_arr;
306
      sep_out_im_arr <= fft_out_im_arr;
307
      sep_out_val    <= fft_out_val;
308
    end generate;
309
 
310
    ---------------------------------------------------------------
311
    -- OUTPUT QUANTIZER
312
    ---------------------------------------------------------------
313
    gen_output_requantizers : for I in g_fft.wb_factor-1 downto 0 generate
314 5 danv
      u_requantize_output_re : entity astron_requantize_lib.common_requantize
315 2 danv
      generic map (
316
        g_representation      => "SIGNED",
317
        g_lsb_w               => c_out_scale_w,
318
        g_lsb_round           => TRUE,
319
        g_lsb_round_clip      => FALSE,
320
        g_msb_clip            => FALSE,
321
        g_msb_clip_symmetric  => FALSE,
322
        g_pipeline_remove_lsb => c_pipeline_remove_lsb,
323
        g_pipeline_remove_msb => 0,
324
        g_in_dat_w            => g_fft.stage_dat_w,
325
        g_out_dat_w           => g_fft.out_dat_w
326
      )
327
      port map (
328
        clk        => clk,
329
        in_dat     => sep_out_re_arr(I),
330
        out_dat    => out_re_arr(I),
331
        out_ovr    => open
332
      );
333
 
334 5 danv
      u_requantize_output_im : entity astron_requantize_lib.common_requantize
335 2 danv
      generic map (
336
        g_representation      => "SIGNED",
337
        g_lsb_w               => c_out_scale_w,
338
        g_lsb_round           => TRUE,
339
        g_lsb_round_clip      => FALSE,
340
        g_msb_clip            => FALSE,
341
        g_msb_clip_symmetric  => FALSE,
342
        g_pipeline_remove_lsb => c_pipeline_remove_lsb,
343
        g_pipeline_remove_msb => 0,
344
        g_in_dat_w            => g_fft.stage_dat_w,
345
        g_out_dat_w           => g_fft.out_dat_w
346
      )
347
      port map (
348
        clk        => clk,
349
        in_dat     => sep_out_im_arr(I),
350
        out_dat    => out_im_arr(I),
351
        out_ovr    => open
352
      );
353
    end generate;
354
 
355
    u_out_val : entity common_components_lib.common_pipeline_sl
356
    generic map (
357
      g_pipeline => c_pipeline_remove_lsb
358
    )
359
    port map (
360
      rst     => rst,
361
      clk     => clk,
362
      in_dat  => sep_out_val,
363
      out_dat => out_val
364
    );
365
 
366
  end generate;
367
end rtl;

powered by: WebSVN 2.1.0

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