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

Subversion Repositories astron_wb_fft

[/] [astron_wb_fft/] [trunk/] [fft_reorder_sepa_pipe.vhd] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 danv
--------------------------------------------------------------------------------
2
--   Author: Harm Jan Pepping : HJP at astron.nl: June 2012
3
--   Copyright (C) 2009-2011
4
--   ASTRON (Netherlands Institute for Radio Astronomy)
5
--   P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
6
--
7
--   This file is part of the UniBoard software suite.
8
--   The file is free software: you can redistribute it and/or modify
9
--   it under the terms of the GNU General Public License as published by
10
--   the Free Software Foundation, either version 3 of the License, or
11
--   (at your option) any later version.
12
--
13
--   This program is distributed in the hope that it will be useful,
14
--   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
--   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
--   GNU General Public License for more details.
17
--
18
--   You should have received a copy of the GNU General Public License
19
--   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
--------------------------------------------------------------------------------
21
--
22
-- Purpose: This unit performs the reordering and the separation for the two real
23
--          input option of the complex fft.
24
--          It can also perform only one of the two functions(specified via generics).
25
--
26
-- Description: The incoming data is written (normal or reordered, based on g_bit_flip)
27
--              to the first page of a dual page memory. When the first page is full, 
28
--              the write process will continue on the second page. Meanwhile the read 
29
--              process will start to read the first page. The read process can include 
30
--              the separation function or not(based on g_separate). 
31
--              The size of the dual page memory is determined by g_nof_points. 
32
--
33
-- Remarks: . This unit is only suitable for the pipelined fft (fft_r2_pipe).
34
-- 
35
 
36
library ieee, common_pkg_lib, common_counter_lib, common_ram_lib;
37
use IEEE.std_logic_1164.all;
38
use IEEE.numeric_std.all;
39
use common_pkg_lib.common_pkg.all;
40
use work.fft_pkg.all;
41
 
42
entity fft_reorder_sepa_pipe is
43
  generic   (
44
    g_nof_points  : natural := 8;
45
    g_bit_flip    : boolean := true;  -- apply index flip to have bins in incrementing frequency order
46
    g_fft_shift   : boolean := false; -- apply fft_shift to have negative bin frequencies first for complex input
47
    g_dont_flip_channels : boolean := false;  -- set true to preserve the channel interleaving when g_bit_flip is true, otherwise the channels get separated in time when g_bit_flip is true
48
    g_separate    : boolean := true;  -- apply separation bins for two real inputs
49
    g_nof_chan    : natural := 0      -- Exponent of nr of subbands (0 means 1 subband, 1 => 2 sb, 2 => 4 sb, etc )
50
  );
51
  port (
52
    clk     : in  std_logic;
53
    rst     : in  std_logic;
54
    in_dat  : in  std_logic_vector;
55
    in_val  : in  std_logic;
56
    out_dat : out std_logic_vector;
57
    out_val : out std_logic
58
  );
59
end entity fft_reorder_sepa_pipe;
60
 
61
architecture rtl of fft_reorder_sepa_pipe is
62
 
63
  constant c_nof_channels : natural := 2**g_nof_chan;
64
  constant c_dat_w        : natural := in_dat'length;
65
  constant c_page_size    : natural := g_nof_points*c_nof_channels;
66
  constant c_adr_points_w : natural := ceil_log2(g_nof_points);
67
  constant c_adr_chan_w   : natural := g_nof_chan;
68
  constant c_adr_tot_w    : natural := c_adr_points_w + c_adr_chan_w;
69
 
70
  signal adr_points_cnt : std_logic_vector(c_adr_points_w -1 downto 0);
71
  signal adr_chan_cnt   : std_logic_vector(c_adr_chan_w   -1 downto 0);
72
  signal adr_tot_cnt    : std_logic_vector(c_adr_tot_w    -1 downto 0);
73
 
74
  signal adr_fft_flip   : std_logic_vector(c_adr_points_w-1 downto 0);
75
  signal adr_fft_shift  : std_logic_vector(c_adr_points_w-1 downto 0);
76
 
77
  signal next_page : std_logic;
78
 
79
  signal cnt_ena   : std_logic;
80
 
81
  signal wr_en     : std_logic;
82
  signal wr_adr    : std_logic_vector(c_adr_tot_w-1 downto 0);
83
  signal wr_dat    : std_logic_vector(c_dat_w-1 downto 0);
84
 
85
  signal rd_en     : std_logic;
86
  signal rd_adr_up   : std_logic_vector(c_adr_points_w downto 0);
87
  signal rd_adr_down : std_logic_vector(c_adr_points_w downto 0);  -- use intermediate rd_adr_down that has 1 bit extra to avoid truncation warning with TO_UVEC()
88
  signal rd_adr    : std_logic_vector(c_adr_tot_w-1 downto 0);
89
  signal rd_dat    : std_logic_vector(c_dat_w-1 downto 0);
90
  signal rd_val    : std_logic;
91
 
92
  signal out_dat_i : std_logic_vector(c_dat_w-1 downto 0);
93
  signal out_val_i : std_logic;
94
 
95
  type   state_type is (s_idle, s_run_separate, s_run_normal);
96
 
97
  type reg_type is record
98
    rd_en       : std_logic;   -- The read enable signal to read out the data from the dp memory
99
    switch      : std_logic;   -- Toggel register used for separate functionalilty
100
    count_up    : natural;     -- An upwards counter for read addressing
101
    count_down  : natural;     -- A downwards counter for read addressing
102
    count_chan  : natural;     -- Counter that holds the number of channels for reading. 
103
    state       : state_type;  -- The state machine. 
104
  end record;
105
 
106
  signal r, rin : reg_type;
107
 
108
begin
109
 
110
  out_dat_i <= rd_dat;
111
  out_val_i <= rd_val;
112
 
113
  wr_dat    <= in_dat;
114
  wr_en     <= in_val;
115
 
116
  next_page <= '1' when unsigned(adr_tot_cnt) = c_page_size-1  and wr_en='1' else '0';
117
 
118
  adr_tot_cnt <= adr_chan_cnt & adr_points_cnt;
119
 
120
  adr_fft_flip <= flip(adr_points_cnt);      -- flip the addresses to perform the bit-reversed reorder
121
  adr_fft_shift <= fft_shift(adr_fft_flip);  -- invert MSbit for fft_shift
122
 
123
  gen_complex : if g_separate=false generate
124
    no_bit_flip : if g_bit_flip=false generate
125
      wr_adr <= adr_tot_cnt;
126
    end generate;
127
    gen_bit_flip_spectrum_and_channels : if g_bit_flip=true and g_dont_flip_channels=false generate -- the channels get separated in time
128
      gen_no_fft_shift_sac : if g_fft_shift=false generate
129
        wr_adr <= adr_chan_cnt & adr_fft_flip;
130
      end generate;
131
      gen_fft_shift_sac : if g_fft_shift=true generate
132
        wr_adr <= adr_chan_cnt & adr_fft_shift;
133
      end generate;
134
    end generate;
135
    gen_bit_flip_spectrum_only : if g_bit_flip=true and g_dont_flip_channels=true generate  -- the channel interleaving in time is preserved
136
      gen_no_fft_shift_so : if g_fft_shift=false generate
137
        wr_adr <= adr_fft_flip & adr_chan_cnt;
138
      end generate;
139
      gen_fft_shift_so : if g_fft_shift=true generate
140
        wr_adr <= adr_fft_shift & adr_chan_cnt;
141
      end generate;
142
    end generate;
143
  end generate;
144
  gen_two_real : if g_separate=true generate
145
    gen_bit_flip_spectrum_and_channels : if g_dont_flip_channels=false generate -- the channels get separated in time
146
      wr_adr <= adr_chan_cnt & adr_fft_flip;
147
    end generate;
148
    gen_bit_flip_spectrum_only : if g_dont_flip_channels=true generate  -- the channel interleaving in time is preserved
149
      wr_adr <= adr_fft_flip & adr_chan_cnt;
150
    end generate;
151
  end generate;
152
 
153
  u_adr_point_cnt : entity common_counter_lib.common_counter
154
  generic map(
155
    g_latency   => 1,
156
    g_init      => 0,
157
    g_width     => ceil_log2(g_nof_points)
158
  )
159
  PORT MAP (
160
    rst     => rst,
161
    clk     => clk,
162
    cnt_en  => cnt_ena,
163
    count   => adr_points_cnt
164
  );
165
 
166
  -- Generate on c_nof_channels to avoid simulation warnings on TO_UINT(adr_chan_cnt) when adr_chan_cnt is a NULL array
167
  one_chan : if c_nof_channels=1 generate
168
    cnt_ena <= '1' when in_val = '1' else '0';
169
  end generate;
170
  more_chan : if c_nof_channels>1 generate
171
    cnt_ena <= '1' when in_val = '1' and TO_UINT(adr_chan_cnt) = c_nof_channels-1 else '0';
172
  end generate;
173
 
174
  u_adr_chan_cnt : entity common_counter_lib.common_counter
175
  generic map(
176
    g_latency   => 1,
177
    g_init      => 0,
178
    g_width     => g_nof_chan
179
  )
180
  PORT MAP (
181
    rst     => rst,
182
    clk     => clk,
183
    cnt_en  => in_val,
184
    count   => adr_chan_cnt
185
  );
186
 
187
  u_buff : entity common_ram_lib.common_paged_ram_r_w
188
  generic map (
189
    g_str             => "use_adr",
190
    g_data_w          => c_dat_w,
191
    g_nof_pages       => 2,
192
    g_page_sz         => c_page_size,
193
    g_wr_start_page   => 0,
194
    g_rd_start_page   => 1,
195
    g_rd_latency      => 1
196
  )
197
  port map (
198
    rst          => rst,
199
    clk          => clk,
200
    wr_next_page => next_page,
201
    wr_adr       => wr_adr,
202
    wr_en        => wr_en,
203
    wr_dat       => wr_dat,
204
    rd_next_page => next_page,
205
    rd_adr       => rd_adr,
206
    rd_en        => rd_en,
207
    rd_dat       => rd_dat,
208
    rd_val       => rd_val
209
  );
210
 
211
  -- If the separate functionality is enabled the read address will 
212
  -- be composed of an up and down counter that are interleaved. This is
213
  -- reflected in the s_run_separate state. 
214
  -- The process facilitates the first stage of the separate function
215
  -- It generates the read address in order to 
216
  -- create the data stream that is required for the separate
217
  -- block. The order for a 1024 ponit FFT is:
218
  -- X(0), X(1024), X(1), X(1023), X(2), X(1022), etc...              
219
  --          |
220
  --          |
221
  --       This value is X(0), because modulo N addressing is used. 
222
  --
223
  -- If separate functionality is disbaled a "normal" coun ter is used 
224
  -- to read out the dual page memory. State: s_run_normal
225
 
226
  comb : process(r, rst, next_page)
227
    variable v : reg_type;
228
  begin
229
 
230
    v := r;
231
    v.rd_en := '0';
232
 
233
    case r.state is
234
            when s_idle =>
235
        if(next_page = '1') then               -- Both counters are reset on page turn. 
236
          v.rd_en        := '1';
237
          v.switch       := '0';
238
          v.count_up     := 0;
239
          if(g_separate=true) then             -- Choose the appropriate run state 
240
            v.count_chan := 0;
241
            v.count_down := g_nof_points;
242
            v.state      := s_run_separate;
243
          else
244
            v.state      := s_run_normal;
245
          end if;
246
        end if;
247
 
248
            when s_run_separate =>
249
        v.rd_en      := '1';
250
        if(r.switch = '0') then
251
          v.switch   := '1';
252
          v.count_up := r.count_up + 1;
253
        end if;
254
 
255
        if(r.switch = '1') then
256
          v.switch     := '0';
257
          v.count_down := r.count_down - 1;
258
        end if;
259
 
260
        if(next_page = '1') then                 -- Both counters are reset on page turn. 
261
          v.count_up   := 0;
262
          v.count_down := g_nof_points;
263
          v.count_chan := 0;
264
        elsif(r.count_up = g_nof_points/2 and r.count_chan < c_nof_channels-1) then  -- 
265
          v.count_up   := 0;
266
          v.count_down := g_nof_points;
267
          v.count_chan := r.count_chan + 1;
268
        elsif(r.count_up = g_nof_points/2) then  -- Pagereading is done, but there is not yet new data available
269
          v.rd_en      := '0';
270
          v.state      := s_idle;
271
        end if;
272
 
273
      when s_run_normal =>
274
        v.rd_en      := '1';
275
        if(next_page = '1') then                -- Counters is reset on page turn.         
276
          v.count_up := 0;
277
        elsif(r.count_up = c_page_size-1) then  -- Pagereading is done, but there is not yet new data available 
278
          v.rd_en    := '0';
279
          v.state    := s_idle;
280
        else
281
          v.count_up := r.count_up + 1;
282
        end if;
283
 
284
            when others =>
285
                  v.state := s_idle;
286
 
287
          end case;
288
 
289
    if(rst = '1') then
290
      v.switch     := '0';
291
      v.rd_en      := '0';
292
      v.count_up   := 0;
293
      v.count_down := 0;
294
      v.count_chan := 0;
295
      v.state      := s_idle;
296
    end if;
297
 
298
    rin <= v;
299
 
300
  end process comb;
301
 
302
  regs : process(clk)
303
  begin
304
    if rising_edge(clk) then
305
      r <= rin;
306
    end if;
307
  end process;
308
 
309
  rd_en  <= r.rd_en;
310
 
311
  gen_separate : if g_separate=true generate
312
    -- The read address toggles between the upcounter and the downcounter.
313
    -- Modulo N addressing is done with the TO_UVEC function.
314
    rd_adr_up   <= TO_UVEC(r.count_up,   c_adr_points_w+1);  -- eg.    0 .. 512
315
    rd_adr_down <= TO_UVEC(r.count_down, c_adr_points_w+1);  -- eg. 1024 .. 513, use 1 bit more to avoid truncation warning on 1024 ^= 0
316
    rd_adr <= TO_UVEC(r.count_chan, c_adr_chan_w) & rd_adr_up(  c_adr_points_w-1 DOWNTO 0) when r.switch = '0' else
317
              TO_UVEC(r.count_chan, c_adr_chan_w) & rd_adr_down(c_adr_points_w-1 DOWNTO 0);
318
    -- The data that is read from the memory is fed to the separate block
319
    -- that performs the 2nd stage of separation. The output of the 
320
    -- separate unit is connected to the output of rtwo_order_separate unit. 
321
    -- The 2nd stage of the separate funtion is performed:
322
    u_separate : entity work.fft_sepa
323
    port map (
324
      clk     => clk,
325
      rst     => rst,
326
      in_dat  => out_dat_i,
327
      in_val  => out_val_i,
328
      out_dat => out_dat,
329
      out_val => out_val
330
    );
331
  end generate;
332
 
333
  -- If the separate functionality is disabled the 
334
  -- read address is received from the address counter and
335
  -- the output signals are directly driven. 
336
  gen_no_separate : if g_separate=false generate
337
    rd_adr  <= TO_UVEC(r.count_up, c_adr_tot_w);
338
    out_dat <= out_dat_i;
339
    out_val <= out_val_i;
340
  end generate;
341
 
342
end rtl;
343
 
344
 

powered by: WebSVN 2.1.0

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