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 5

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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