1 |
2 |
danv |
-------------------------------------------------------------------------------
|
2 |
|
|
--
|
3 |
|
|
-- Copyright (C) 2011
|
4 |
|
|
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
|
5 |
|
|
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
|
6 |
|
|
--
|
7 |
|
|
-- This program is free software: you can redistribute it and/or modify
|
8 |
|
|
-- it under the terms of the GNU General Public License as published by
|
9 |
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
10 |
|
|
-- (at your option) any later version.
|
11 |
|
|
--
|
12 |
|
|
-- This program is distributed in the hope that it will be useful,
|
13 |
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
|
|
-- GNU General Public License for more details.
|
16 |
|
|
--
|
17 |
|
|
-- You should have received a copy of the GNU General Public License
|
18 |
|
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19 |
|
|
--
|
20 |
|
|
-------------------------------------------------------------------------------
|
21 |
|
|
|
22 |
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib, mm_lib, common_ram_lib;
|
23 |
|
|
USE IEEE.STD_LOGIC_1164.ALL;
|
24 |
|
|
USE IEEE.NUMERIC_STD.ALL;
|
25 |
|
|
use IEEE.std_logic_textio.all;
|
26 |
|
|
USE STD.textio.all;
|
27 |
|
|
USE common_pkg_lib.common_pkg.ALL;
|
28 |
|
|
USE common_ram_lib.common_ram_pkg.ALL;
|
29 |
|
|
USE common_pkg_lib.tb_common_pkg.ALL;
|
30 |
|
|
USE mm_lib.tb_common_mem_pkg.ALL;
|
31 |
|
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
32 |
|
|
USE work.fft_pkg.ALL;
|
33 |
|
|
|
34 |
|
|
PACKAGE tb_fft_pkg IS
|
35 |
|
|
|
36 |
|
|
CONSTANT c_fft_nof_subbands_max : NATURAL := 256;
|
37 |
|
|
|
38 |
|
|
SUBTYPE t_fft_sst_arr IS t_slv_64_arr(c_fft_nof_subbands_max-1 DOWNTO 0); -- use subtype to allow using assignments via t_slv_64_arr as well
|
39 |
|
|
TYPE t_fft_sst_arr2 IS ARRAY (INTEGER RANGE <>) OF t_fft_sst_arr; -- Private procedures
|
40 |
|
|
|
41 |
|
|
-- map fft output index to bin frequency
|
42 |
|
|
function fft_index_to_bin_frequency(wb_factor, nof_points, index : natural; use_reorder, use_fft_shift, use_separate : boolean) return natural;
|
43 |
|
|
|
44 |
|
|
-- use out_val and out_val_cnt to determine the FFT output bin frequency and channel
|
45 |
|
|
procedure proc_fft_out_control(wb_factor : natural;
|
46 |
|
|
nof_points : natural;
|
47 |
|
|
nof_channels : natural;
|
48 |
|
|
use_reorder : boolean;
|
49 |
|
|
use_fft_shift : boolean;
|
50 |
|
|
use_separate : boolean;
|
51 |
|
|
signal out_val_cnt : in natural; -- count at sclk sample rate
|
52 |
|
|
signal out_val : in std_logic;
|
53 |
|
|
signal out_val_a : out std_logic;
|
54 |
|
|
signal out_val_b : out std_logic;
|
55 |
|
|
signal out_channel : out natural;
|
56 |
|
|
signal out_bin : out natural;
|
57 |
|
|
signal out_bin_cnt : out natural);
|
58 |
|
|
|
59 |
|
|
PROCEDURE proc_read_input_file(SIGNAL clk : IN STD_LOGIC;
|
60 |
|
|
SIGNAL in_file_data : OUT t_integer_matrix;
|
61 |
|
|
SIGNAL in_file_sync : OUT STD_LOGIC_VECTOR;
|
62 |
|
|
SIGNAL in_file_val : OUT STD_LOGIC_VECTOR;
|
63 |
|
|
file_name : IN STRING);
|
64 |
|
|
|
65 |
|
|
PROCEDURE proc_read_input_file(SIGNAL clk : IN STD_LOGIC; -- Same read procedure for data files that do not contain a valid and sync column
|
66 |
|
|
SIGNAL in_file_data : OUT t_integer_matrix;
|
67 |
|
|
file_name : IN STRING);
|
68 |
|
|
|
69 |
|
|
|
70 |
|
|
PROCEDURE proc_fft_read_subband_statistics_memory(CONSTANT c_fft_lane : IN NATURAL;
|
71 |
|
|
CONSTANT c_fft : IN t_fft;
|
72 |
|
|
SIGNAL clk : IN STD_LOGIC;
|
73 |
|
|
SIGNAL mm_mosi : OUT t_mem_mosi;
|
74 |
|
|
SIGNAL mm_miso : IN t_mem_miso;
|
75 |
|
|
SIGNAL statistics_arr : OUT t_slv_64_arr);
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
-- Private procedures
|
79 |
|
|
PROCEDURE proc_read_subband_stats(CONSTANT nof_subbands : IN NATURAL;
|
80 |
|
|
CONSTANT offset : IN NATURAL;
|
81 |
|
|
SIGNAL clk : IN STD_LOGIC;
|
82 |
|
|
SIGNAL mm_mosi : OUT t_mem_mosi;
|
83 |
|
|
SIGNAL mm_miso : IN t_mem_miso;
|
84 |
|
|
VARIABLE result : OUT t_slv_64_arr);
|
85 |
|
|
|
86 |
|
|
|
87 |
|
|
-- PROCEDURE proc_prepare_input_data(CONSTANT nof_subbands : IN NATURAL;
|
88 |
|
|
-- CONSTANT nof_inputs : IN NATURAL;
|
89 |
|
|
-- CONSTANT nof_input_streams : IN NATURAL;
|
90 |
|
|
-- CONSTANT input_stream_number : IN NATURAL;
|
91 |
|
|
-- VARIABLE re_arr : OUT t_integer_arr;
|
92 |
|
|
-- VARIABLE im_arr : OUT t_integer_arr;
|
93 |
|
|
-- file_name : IN STRING);
|
94 |
|
|
|
95 |
|
|
END tb_fft_pkg;
|
96 |
|
|
|
97 |
|
|
PACKAGE BODY tb_fft_pkg IS
|
98 |
|
|
|
99 |
|
|
function fft_index_to_bin_frequency(wb_factor, nof_points, index : natural; use_reorder, use_fft_shift, use_separate : boolean) return natural is
|
100 |
|
|
-- Purpose: map fft output index to bin frequency
|
101 |
|
|
-- Description:
|
102 |
|
|
-- The input index counts the bins as they are output by the HDL implementation of the FFT.
|
103 |
|
|
-- This function maps this index to the corresponding bin frequency in the reference FFT.
|
104 |
|
|
-- For the complex input reference FFT the assumption is that the bins are in fft_shift(fft())
|
105 |
|
|
-- order, so first the negative frequencies, then 0 and the positive frequencies. For
|
106 |
|
|
-- the real input reference FFT only 0 and the positive frequency bins are available.
|
107 |
|
|
--
|
108 |
|
|
-- For a N=8 point (complex) FFT the FFT index corresponds to FFT bin frequency according to:
|
109 |
|
|
--
|
110 |
|
|
-- 0 1 2 3 4 5 6 7 -- index i
|
111 |
|
|
-- 0 4 2 6 1 5 3 7 -- flip(i) : FFT bin frequency in bit-reversed index output order
|
112 |
|
|
-- 0 1 2 3 4 5 6 7 -- flip(flip(i)) = i : FFT bin frequency after bit-reversed index flip
|
113 |
|
|
-- yields Matlab fft() output order starting with
|
114 |
|
|
-- [0 Hz, pos freqs incrementing, neg freqs incrementing]
|
115 |
|
|
-- 4 5 6 7 0 1 2 3 -- fft_shift(i) : FFT bin frequency after bit-reversed index flip and
|
116 |
|
|
-- fft_shift yields Matlab fft_shift(fft()) output order:
|
117 |
|
|
-- [neg freqs incrementing, 0 Hz in the center, pos
|
118 |
|
|
-- freqs incrementing]
|
119 |
|
|
-- 1 5 3 7 0 4 2 6 -- flip(fft_shift(i))
|
120 |
|
|
-- 4 0 6 2 5 1 7 3 -- fft_shift(flip(i)) : the order of fft_shift() and flip() matters
|
121 |
|
|
--
|
122 |
|
|
-- For real input only the 0 and positive frequency bins need to be kept:
|
123 |
|
|
--
|
124 |
|
|
-- 0 1 2 3
|
125 |
|
|
--
|
126 |
|
|
-- The FFT needs to buffer the complex FFT output to be able to separate the FFT for two real
|
127 |
|
|
-- inputs, because it needs access at indices N-m and m to do the separate.
|
128 |
|
|
-- Therefore when use_separate=true then the use_reorder index flip is also done to have the bin
|
129 |
|
|
-- frequencies in increasing order. The use_fft_shift is not applicable for real input.
|
130 |
|
|
--
|
131 |
|
|
-- For the complex FFT the index flip and fft_shift both require reordering in time, so buffering
|
132 |
|
|
-- of the FFT output. The fft_shift is only useful after the index flip. Therefore when
|
133 |
|
|
-- use_fft_shift=true then require that use_reorder=true.
|
134 |
|
|
--
|
135 |
|
|
-- The bit-reverse index is a flip of the index bits. The flip() is the same as the inverse flip(),
|
136 |
|
|
-- so index = flip(flip(index)). For wb_factor = 1 the flip() is done by use_reorder. For
|
137 |
|
|
-- wb_factor > 1 the use_reorder implies that both the pipelined sections and the parallel section
|
138 |
|
|
-- do there local flips. This combination of P serial flips and 1 parallel flip is not the same
|
139 |
|
|
-- as the index flip.
|
140 |
|
|
--
|
141 |
|
|
-- The fft_shift() inverts the MSbit of the index. The fft_shift() is the same as the inverse
|
142 |
|
|
-- fft_shift(), so index = fft_shift(fft_shift(index)).
|
143 |
|
|
--
|
144 |
|
|
-- The index counts from 0..nof_points-1. For wb_factor>1 the index first counts parallel over
|
145 |
|
|
-- the P wide band streams and then serially. The transpose(i, P, N) function in common_pkg shows
|
146 |
|
|
-- how the index counts over the P parallel streams and in time:
|
147 |
|
|
--
|
148 |
|
|
-- i = 0 1 2 3 4 5 6 7
|
149 |
|
|
-- t=0 1 2 3 p=
|
150 |
|
|
-- transpose(i, 2, 4) = 0 2 4 6 1 3 5 7 : 0 2 4 6 0
|
151 |
|
|
-- 1 3 5 7 1
|
152 |
|
|
--
|
153 |
|
|
-- t=0 1 2 3 p=
|
154 |
|
|
-- transpose(i, 4, 2) = 0 4 1 5 2 6 3 7 : 0 4 0
|
155 |
|
|
-- 1 5 1
|
156 |
|
|
-- 2 6 2
|
157 |
|
|
-- 3 7 3
|
158 |
|
|
--
|
159 |
|
|
-- In the HDL testbench the index i counts the FFT output valid samples. This index has to be
|
160 |
|
|
-- related to the bin frequency of the HDL FFT and to the same bin frequency in the Matlab
|
161 |
|
|
-- reference data, to be able to verify the bin frequency output value.
|
162 |
|
|
--
|
163 |
|
|
-- Example: wb_factor = 1
|
164 |
|
|
--
|
165 |
|
|
-- The default complex input FFT bit-reversed bin order and the Matlab reference bin order
|
166 |
|
|
-- can relate to i as follows:
|
167 |
|
|
--
|
168 |
|
|
-- [scrambled bins] [0, pos, neg bins] [neg, 0, pos bins]
|
169 |
|
|
-- b=0 4 2 6 1 5 3 7 --> flip(i) --> b=0 1 2 3 4 5 6 7 --> fft_shift(i) --> b=4 5 6 7 0 1 2 3
|
170 |
|
|
-- i=0 1 2 3 4 5 6 7 i=0 1 2 3 4 5 6 7 i=0 1 2 3 4 5 6 7
|
171 |
|
|
--
|
172 |
|
|
-- The two real input FFT bin order (with A via real input and B via imaginary input) and
|
173 |
|
|
-- Matlab reference bin order relate to i as follows:
|
174 |
|
|
--
|
175 |
|
|
-- [0, pos; alternating A,B]
|
176 |
|
|
-- b=0 0 1 1 2 2 3 3 --> b = i/2
|
177 |
|
|
-- i=0 1 2 3 4 5 6 7
|
178 |
|
|
--
|
179 |
|
|
-- Which bins the index i represents depends on the HDL generics use_reorder, use_fft_shift
|
180 |
|
|
-- and use separate.
|
181 |
|
|
--
|
182 |
|
|
-- nof_points = 32 : index = 0..nof_points-1 = 0..31
|
183 |
|
|
--
|
184 |
|
|
-- index i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
185 |
|
|
-- fft_shift(i) 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
186 |
|
|
-- flip(i) 0 16 8 24 4 20 12 28 2 18 10 26 6 22 14 30 1 17 9 25 5 21 13 29 3 19 11 27 7 23 15 31
|
187 |
|
|
-- fft_shift(flip(i)) 16 0 24 8 20 4 28 12 18 2 26 10 22 6 30 14 17 1 25 9 21 5 29 13 19 3 27 11 23 7 31 15
|
188 |
|
|
-- i/2 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15
|
189 |
|
|
--
|
190 |
|
|
-- Conclusion:-
|
191 |
|
|
-- use_reorder use_fft_shift use_separate name reference bin frequency:
|
192 |
|
|
-- false false false Complex b = fft_shift(flip(i))
|
193 |
|
|
-- true false false Complex reordered b = fft_shift(i)
|
194 |
|
|
-- true true false Complex fft_shifted b = i
|
195 |
|
|
-- true false true Two real reordered b = i/2
|
196 |
|
|
--
|
197 |
|
|
-- Example: wb_factor = 4
|
198 |
|
|
--
|
199 |
|
|
-- The default complex input FFT bit-reversed bin order and the Matlab reference bin order
|
200 |
|
|
-- can relate to i as follows in wideband parallel order:
|
201 |
|
|
--
|
202 |
|
|
-- [scrambled bins] --> flip() --> [0, pos, neg bins] --> fft_shift() --> [neg, 0, pos bins]
|
203 |
|
|
-- b=0 4 2 6 1 5 3 7 b=0 4 8 12 16 20 24 28 b=16 20 24 28 0 4 8 12
|
204 |
|
|
-- 16 20 18 22 17 21 19 23 1 5 9 13 17 21 25 29 17 21 25 29 1 5 9 13
|
205 |
|
|
-- 8 12 10 14 9 13 11 15 2 6 10 14 18 22 26 30 18 22 26 30 2 6 10 14
|
206 |
|
|
-- 24 28 26 30 25 29 27 31 3 7 11 15 19 23 27 31 19 23 27 31 3 7 11 15
|
207 |
|
|
--
|
208 |
|
|
-- i=0 4 8 12 16 20 24 28 i=0 4 8 12 16 20 24 28 i= 0 4 8 12 16 20 24 28
|
209 |
|
|
-- 1 5 9 13 17 21 25 29 1 5 9 13 17 21 25 29 1 5 9 13 17 21 25 29
|
210 |
|
|
-- 2 6 10 14 18 22 26 30 2 6 10 14 18 22 26 30 2 6 10 14 18 22 26 30
|
211 |
|
|
-- 3 7 11 15 19 23 27 31 3 7 11 15 19 23 27 31 3 7 11 15 19 23 27 31
|
212 |
|
|
--
|
213 |
|
|
-- In the serial order this becomes:
|
214 |
|
|
--
|
215 |
|
|
-- [scrambled bins] 0 16 8 24 4 20 12 28 2 18 10 26 6 22 14 30 1 17 9 25 5 21 13 29 3 19 11 27 7 23 15 31
|
216 |
|
|
-- [0, pos, neg bins] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
217 |
|
|
-- [neg, 0, pos bins] 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
218 |
|
|
-- i= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
219 |
|
|
--
|
220 |
|
|
-- The index flip in the HDL that is done in the P pipelined FFT sections and then in the
|
221 |
|
|
-- parallel FFT section results in:
|
222 |
|
|
--
|
223 |
|
|
-- [scrambled bins] flip serial() --> flip parallel()
|
224 |
|
|
-- b=0 4 2 6 1 5 3 7 b=0 1 2 3 4 5 6 7 b=0 1 2 3 4 5 6 7
|
225 |
|
|
-- 16 20 18 22 17 21 19 23 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15
|
226 |
|
|
-- 8 12 10 14 9 13 11 15 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
227 |
|
|
-- 24 28 26 30 25 29 27 31 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31
|
228 |
|
|
--
|
229 |
|
|
-- i=0 4 8 12 16 20 24 28 i=0 4 8 12 16 20 24 28 i=0 4 8 12 16 20 24 28
|
230 |
|
|
-- 1 5 9 13 17 21 25 29 1 5 9 13 17 21 25 29 1 5 9 13 17 21 25 29
|
231 |
|
|
-- 2 6 10 14 18 22 26 30 2 6 10 14 18 22 26 30 2 6 10 14 18 22 26 30
|
232 |
|
|
-- 3 7 11 15 19 23 27 31 3 7 11 15 19 23 27 31 3 7 11 15 19 23 27 31
|
233 |
|
|
--
|
234 |
|
|
-- In the serial order this becomes:
|
235 |
|
|
--
|
236 |
|
|
-- [scrambled bins] 0 16 8 24 4 20 12 28 2 18 10 26 6 22 14 30 1 17 9 25 5 21 13 29 3 19 11 27 7 23 15 31
|
237 |
|
|
-- [flip serial()] 0 16 8 24 1 17 9 25 2 18 10 26 3 19 11 27 4 20 12 28 5 21 13 29 6 22 14 30 7 23 15 31
|
238 |
|
|
-- [flip parallel()] 0 8 16 24 1 9 17 25 2 10 18 26 3 11 19 27 4 12 20 28 5 13 21 29 6 14 22 30 7 15 23 31
|
239 |
|
|
--
|
240 |
|
|
-- Note that the order of flip serial() and flip parallel() does not matter. However the combination of
|
241 |
|
|
-- flip serial() and flip parallel() is not the same as a single flip(), because a single flip at once
|
242 |
|
|
-- yields the [0, pos, neg bins] order. To get from i to the flip serial() and flip parallel() order of
|
243 |
|
|
-- the HDL output index i requires a transpose(i,8,4).
|
244 |
|
|
--
|
245 |
|
|
-- i= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
246 |
|
|
-- transpose(i,8,4) = 0 8 16 24 1 9 17 25 2 10 18 26 3 11 19 27 4 12 20 28 5 13 21 29 6 14 22 30 7 15 23 31
|
247 |
|
|
-- transpose(i,8,4) = 0 8 16 24
|
248 |
|
|
-- 1 9 17 25
|
249 |
|
|
-- 2 10 18 26
|
250 |
|
|
-- 3 11 19 27
|
251 |
|
|
-- 4 12 20 28
|
252 |
|
|
-- 5 13 21 29
|
253 |
|
|
-- 6 14 22 30
|
254 |
|
|
-- 7 15 23 31
|
255 |
|
|
--
|
256 |
|
|
-- transpose(i,4,8) = 0 4 8 12 16 20 24 28 1 5 9 13 17 21 25 29 2 6 10 14 18 22 26 30 3 7 11 15 19 23 27 31
|
257 |
|
|
-- transpose(i,4,8) = 0 4 8 12 16 20 24 28
|
258 |
|
|
-- 1 5 9 13 17 21 25 29
|
259 |
|
|
-- 2 6 10 14 18 22 26 30
|
260 |
|
|
-- 3 7 11 15 19 23 27 31
|
261 |
|
|
--
|
262 |
|
|
-- For the wideband two real input FFT bin order (with A via real input and B via imaginary input) the
|
263 |
|
|
-- the HDL does the flip serial and flip parallel (so use_reorder) and an additional reorder after the
|
264 |
|
|
-- FFT. The output order then becomes:
|
265 |
|
|
--
|
266 |
|
|
-- [0, pos]
|
267 |
|
|
-- [A B A B A B A B]
|
268 |
|
|
-- b=0 0 1 1 2 2 3 3 b = i/2 + wb_factor
|
269 |
|
|
-- 4 4 5 5 6 6 7 7
|
270 |
|
|
-- 8 8 9 9 10 10 11 11
|
271 |
|
|
-- 12 12 13 13 14 14 15 15
|
272 |
|
|
--
|
273 |
|
|
-- i=0 4 8 12 16 20 24 28
|
274 |
|
|
-- 1 5 9 13 17 21 25 29
|
275 |
|
|
-- 2 6 10 14 18 22 26 30
|
276 |
|
|
-- 3 7 11 15 19 23 27 31
|
277 |
|
|
--
|
278 |
|
|
-- In the serial order this becomes:
|
279 |
|
|
-- A A A A B B B B A A A A B B B B A A A A B B B B A A A A B B B B
|
280 |
|
|
-- [Two real] = 0 4 8 12 0 4 8 12 1 5 9 13 1 5 9 13 2 6 10 14 2 6 10 14 3 7 11 15 3 7 11 15
|
281 |
|
|
-- i= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
282 |
|
|
-- transpose(i,8,4) = 0 8 16 24 1 9 17 25 2 10 18 26 3 11 19 27 4 12 20 28 5 13 21 29 6 14 22 30 7 15 23 31
|
283 |
|
|
-- transpose(i,8,4)/2 = 0 4 8 12 0 4 8 12 1 5 9 13 1 5 9 13 2 6 10 14 2 6 10 14 3 7 11 15 3 7 11 15
|
284 |
|
|
--
|
285 |
|
|
-- Conclusion:
|
286 |
|
|
-- use_reorder use_fft_shift use_separate name reference bin frequency:
|
287 |
|
|
-- false false false Complex fft_shift(flip(i))
|
288 |
|
|
-- true false false Complex reordered fft_shift(transpose(i,4,8)) (See remark *)
|
289 |
|
|
-- true true false Complex fft_shifted transpose(i,4,8) (See remark *)
|
290 |
|
|
-- true false true Two real reordered transpose(i,4,8)/2 (See remark *)
|
291 |
|
|
--
|
292 |
|
|
-- Remarks:
|
293 |
|
|
-- * in the HDL use_fft_shift is not (yet) supported, so use_fft_shift = FALSE
|
294 |
|
|
-- * for wb_factor > 1 the flip serial() and flip parallel() are better not done, because to fully reorder the
|
295 |
|
|
-- still needs a transpose() that requires a dual buffer after the wideband FFT.
|
296 |
|
|
-- * strangely the analysis expects that transpose(i,8,4) is necessary to compensate for the incomplete
|
297 |
|
|
-- use_reorder (by flip serial and flip parallel), however in practise transpose(i,4,8) is needed to match
|
298 |
|
|
-- the HDL output
|
299 |
|
|
--
|
300 |
|
|
constant c_addr_w : natural := ceil_log2(nof_points);
|
301 |
|
|
|
302 |
|
|
variable v_addr : std_logic_vector(c_addr_w-1 downto 0); -- used to convert index integer into slv
|
303 |
|
|
variable v_index : natural;
|
304 |
|
|
variable v_bin : natural;
|
305 |
|
|
begin
|
306 |
|
|
-- index = i
|
307 |
|
|
if wb_factor=1 then
|
308 |
|
|
-- Single serial data
|
309 |
|
|
if use_separate=false then
|
310 |
|
|
-- Complex input data
|
311 |
|
|
if use_reorder=false then
|
312 |
|
|
-- No HDL index flip
|
313 |
|
|
v_addr := to_uvec(index, c_addr_w);
|
314 |
|
|
v_addr := flip(v_addr);
|
315 |
|
|
v_addr := fft_shift(v_addr); -- b = fft_shift(flip(i))
|
316 |
|
|
else
|
317 |
|
|
-- With HDL index flip
|
318 |
|
|
if use_fft_shift=false then
|
319 |
|
|
-- No HDL fft_shift
|
320 |
|
|
v_addr := to_uvec(index, c_addr_w);
|
321 |
|
|
v_addr := fft_shift(v_addr); -- b = fft_shift(i)
|
322 |
|
|
else
|
323 |
|
|
-- With HDL fft_shift
|
324 |
|
|
v_addr := to_uvec(index, c_addr_w); -- b = i
|
325 |
|
|
end if;
|
326 |
|
|
end if;
|
327 |
|
|
v_bin := to_uint(v_addr);
|
328 |
|
|
else
|
329 |
|
|
-- Two real input data
|
330 |
|
|
v_bin := index / 2; -- b = i/2
|
331 |
|
|
end if;
|
332 |
|
|
else
|
333 |
|
|
-- Wideband parallel data
|
334 |
|
|
if use_separate=false then
|
335 |
|
|
-- Wideband complex input data
|
336 |
|
|
if use_reorder=false then
|
337 |
|
|
-- No HDL pipelined and parallel index flips
|
338 |
|
|
v_addr := to_uvec(index, c_addr_w);
|
339 |
|
|
v_addr := flip(v_addr);
|
340 |
|
|
v_addr := fft_shift(v_addr); -- b = fft_shift(flip(i))
|
341 |
|
|
else
|
342 |
|
|
-- With HDL pipelined and parallel index flips
|
343 |
|
|
if use_fft_shift=false then
|
344 |
|
|
-- No HDL fft_shift
|
345 |
|
|
v_index := transpose(index, wb_factor, nof_points/wb_factor); -- t = transpose(i, 4, 8)
|
346 |
|
|
v_addr := to_uvec(v_index, c_addr_w);
|
347 |
|
|
v_addr := fft_shift(v_addr); -- b = fft_shift(t)
|
348 |
|
|
else
|
349 |
|
|
-- With HDL fft_shift
|
350 |
|
|
v_index := transpose(index, wb_factor, nof_points/wb_factor); -- t = transpose(i, 4, 8)
|
351 |
|
|
v_addr := to_uvec(v_index, c_addr_w); -- b = t
|
352 |
|
|
end if;
|
353 |
|
|
end if;
|
354 |
|
|
v_bin := to_uint(v_addr);
|
355 |
|
|
else
|
356 |
|
|
-- Wideband two real input data
|
357 |
|
|
v_index := transpose(index, wb_factor, nof_points/wb_factor); -- t = transpose(i, 4, 8)
|
358 |
|
|
v_bin := v_index/2; -- b = t/2
|
359 |
|
|
end if;
|
360 |
|
|
end if;
|
361 |
|
|
return v_bin;
|
362 |
|
|
end fft_index_to_bin_frequency;
|
363 |
|
|
|
364 |
|
|
|
365 |
|
|
procedure proc_fft_out_control(wb_factor : natural;
|
366 |
|
|
nof_points : natural;
|
367 |
|
|
nof_channels : natural;
|
368 |
|
|
use_reorder : boolean;
|
369 |
|
|
use_fft_shift : boolean;
|
370 |
|
|
use_separate : boolean;
|
371 |
|
|
signal out_val_cnt : in natural; -- count at sclk sample rate
|
372 |
|
|
signal out_val : in std_logic;
|
373 |
|
|
signal out_val_a : out std_logic;
|
374 |
|
|
signal out_val_b : out std_logic;
|
375 |
|
|
signal out_channel : out natural;
|
376 |
|
|
signal out_bin : out natural;
|
377 |
|
|
signal out_bin_cnt : out natural) is
|
378 |
|
|
-- Purpose: Derive reference control signals from FFT out_val, out_val_cnt
|
379 |
|
|
-- and derive an index per block that can be used to determine
|
380 |
|
|
-- the frequency bin with fft_index_to_bin_frequency().
|
381 |
|
|
-- Description:
|
382 |
|
|
-- The out_val_cnt counts the valid output data from the FFT:
|
383 |
|
|
--
|
384 |
|
|
-- . out_val_a and out_val_b for interleaved output for two real inputs
|
385 |
|
|
-- . out_channel index in range 0:nof_channels-1
|
386 |
|
|
--
|
387 |
|
|
-- Internally a v_index per block is determined that is independent of
|
388 |
|
|
-- nof_channels and then fft_index_to_bin_frequency() is used with the
|
389 |
|
|
-- reorder parameters use_reorder, use_fft_shift, use_separate,
|
390 |
|
|
-- wb_factor to map this v_index to the bin frequency.
|
391 |
|
|
--
|
392 |
|
|
-- . out_bin is bin frequency index within a block
|
393 |
|
|
-- . out_bin_cnt is bin frequency index in the reference data
|
394 |
|
|
--
|
395 |
|
|
variable v_blk_index : natural;
|
396 |
|
|
variable v_index : natural;
|
397 |
|
|
variable v_bin : natural;
|
398 |
|
|
begin
|
399 |
|
|
out_val_a <= '0';
|
400 |
|
|
out_val_b <= '0';
|
401 |
|
|
|
402 |
|
|
if use_separate=true then
|
403 |
|
|
-- Two real input data
|
404 |
|
|
-- Toggle out_val serially starting with wb_factor*A then wb_factor*B
|
405 |
|
|
if out_val_cnt/wb_factor mod c_nof_complex = 0 then
|
406 |
|
|
out_val_a <= out_val;
|
407 |
|
|
else
|
408 |
|
|
out_val_b <= out_val;
|
409 |
|
|
end if;
|
410 |
|
|
end if;
|
411 |
|
|
|
412 |
|
|
if use_reorder=true then
|
413 |
|
|
v_blk_index := out_val_cnt / nof_points; -- each block has nof_points
|
414 |
|
|
out_channel <= v_blk_index mod nof_channels; -- the nof_channels are interleaved per block
|
415 |
|
|
|
416 |
|
|
v_index := out_val_cnt mod nof_points; -- index within a block independent of nof_channels
|
417 |
|
|
|
418 |
|
|
v_bin := fft_index_to_bin_frequency(wb_factor, nof_points, v_index, use_reorder, use_fft_shift, use_separate);
|
419 |
|
|
|
420 |
|
|
out_bin <= v_bin; -- bin frequency in a block
|
421 |
|
|
if use_separate=true then
|
422 |
|
|
-- Two real input data
|
423 |
|
|
out_bin_cnt <= v_bin + (v_blk_index/nof_channels) * (nof_points/c_nof_complex); -- bin index in the half spectrum reference data stream of blocks
|
424 |
|
|
else
|
425 |
|
|
-- Complex input data
|
426 |
|
|
out_bin_cnt <= v_bin + (v_blk_index/nof_channels) * nof_points; -- bin index in the full spectrum reference data stream of blocks
|
427 |
|
|
end if;
|
428 |
|
|
else
|
429 |
|
|
-- Complex input data
|
430 |
|
|
v_blk_index := out_val_cnt / nof_points / nof_channels; -- each block has nof_channels*nof_points
|
431 |
|
|
out_channel <= (out_val_cnt / wb_factor) mod nof_channels; -- the nof_channels are interleaved per wb_factor number of samples
|
432 |
|
|
|
433 |
|
|
v_index := ((out_val_cnt / wb_factor / nof_channels) * wb_factor +
|
434 |
|
|
(out_val_cnt MOD wb_factor)) mod nof_points; -- index within a block independent of nof_channels
|
435 |
|
|
|
436 |
|
|
v_bin := fft_index_to_bin_frequency(wb_factor, nof_points, v_index, use_reorder, use_fft_shift, use_separate);
|
437 |
|
|
|
438 |
|
|
out_bin <= v_bin; -- bin frequency in a block
|
439 |
|
|
out_bin_cnt <= v_bin + v_blk_index * nof_points; -- bin index in the full spectrum reference data stream of blocks
|
440 |
|
|
end if;
|
441 |
|
|
end proc_fft_out_control;
|
442 |
|
|
|
443 |
|
|
|
444 |
|
|
------------------------------------------------------------------------------
|
445 |
|
|
-- PROCEDURE: Read input file.
|
446 |
|
|
-- Reads data (re, im, sync and val) from a file and writes values
|
447 |
|
|
-- to the output signals.
|
448 |
|
|
------------------------------------------------------------------------------
|
449 |
|
|
PROCEDURE proc_read_input_file( SIGNAL clk : IN STD_LOGIC;
|
450 |
|
|
SIGNAL in_file_data : OUT t_integer_matrix;
|
451 |
|
|
SIGNAL in_file_sync : OUT STD_LOGIC_VECTOR;
|
452 |
|
|
SIGNAL in_file_val : OUT STD_LOGIC_VECTOR;
|
453 |
|
|
file_name : IN STRING) IS
|
454 |
|
|
|
455 |
|
|
VARIABLE v_file_status : FILE_OPEN_STATUS;
|
456 |
|
|
FILE v_in_file : TEXT;
|
457 |
|
|
VARIABLE v_log_line : LINE;
|
458 |
|
|
VARIABLE v_input_line : LINE;
|
459 |
|
|
VARIABLE v_index : INTEGER :=0;
|
460 |
|
|
VARIABLE v_comma : CHARACTER;
|
461 |
|
|
VARIABLE v_sync : STD_LOGIC_VECTOR(in_file_sync'RANGE):=(OTHERS => '0');
|
462 |
|
|
VARIABLE v_val : STD_LOGIC_VECTOR(in_file_val'RANGE) :=(OTHERS => '0');
|
463 |
|
|
VARIABLE v_data : t_integer_matrix(in_file_sync'RANGE, 1 to 2) := (OTHERS => (OTHERS => 0));
|
464 |
|
|
BEGIN
|
465 |
|
|
-- wait 1 clock cycle to avoid that the output messages
|
466 |
|
|
-- in the transcript window get lost in the 0 ps start up messages
|
467 |
|
|
proc_common_wait_some_cycles(clk, 1);
|
468 |
|
|
write(v_log_line, string'("reading file : "));
|
469 |
|
|
write(v_log_line, file_name);
|
470 |
|
|
writeline(output, v_log_line);
|
471 |
|
|
proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); -- Open the file with data values for reading
|
472 |
|
|
LOOP
|
473 |
|
|
EXIT WHEN endfile(v_in_file);
|
474 |
|
|
readline(v_in_file, v_input_line);
|
475 |
|
|
|
476 |
|
|
read(v_input_line, v_sync(v_index)); -- sync
|
477 |
|
|
read(v_input_line, v_comma);
|
478 |
|
|
|
479 |
|
|
read(v_input_line, v_val(v_index)); -- valid
|
480 |
|
|
read(v_input_line, v_comma);
|
481 |
|
|
|
482 |
|
|
read(v_input_line, v_data(v_index,1)); -- real
|
483 |
|
|
read(v_input_line, v_comma);
|
484 |
|
|
|
485 |
|
|
read(v_input_line, v_data(v_index,2)); -- imag
|
486 |
|
|
v_index := v_index + 1;
|
487 |
|
|
END LOOP;
|
488 |
|
|
proc_common_close_file(v_file_status, v_in_file); -- Close the file
|
489 |
|
|
write(v_log_line, string'("finished reading file : "));
|
490 |
|
|
write(v_log_line, file_name);
|
491 |
|
|
writeline(output, v_log_line);
|
492 |
|
|
|
493 |
|
|
in_file_data <= v_data;
|
494 |
|
|
in_file_sync <= v_sync;
|
495 |
|
|
in_file_val <= v_val;
|
496 |
|
|
WAIT;
|
497 |
|
|
END proc_read_input_file;
|
498 |
|
|
|
499 |
|
|
------------------------------------------------------------------------------
|
500 |
|
|
-- PROCEDURE: Read input file.
|
501 |
|
|
-- Reads data (re, im, sync and val) from a file and writes values
|
502 |
|
|
-- to the output signals.
|
503 |
|
|
------------------------------------------------------------------------------
|
504 |
|
|
PROCEDURE proc_read_input_file( SIGNAL clk : IN STD_LOGIC;
|
505 |
|
|
SIGNAL in_file_data : OUT t_integer_matrix;
|
506 |
|
|
file_name : IN STRING) IS
|
507 |
|
|
|
508 |
|
|
VARIABLE v_file_status : FILE_OPEN_STATUS;
|
509 |
|
|
FILE v_in_file : TEXT;
|
510 |
|
|
VARIABLE v_log_line : LINE;
|
511 |
|
|
VARIABLE v_input_line : LINE;
|
512 |
|
|
VARIABLE v_index : INTEGER :=0;
|
513 |
|
|
VARIABLE v_comma : CHARACTER;
|
514 |
|
|
VARIABLE v_data : t_integer_matrix(in_file_data'RANGE, 1 to 2) := (OTHERS => (OTHERS => 0));
|
515 |
|
|
BEGIN
|
516 |
|
|
-- wait 1 clock cycle to avoid that the output messages
|
517 |
|
|
-- in the transcript window get lost in the 0 ps start up messages
|
518 |
|
|
proc_common_wait_some_cycles(clk, 1);
|
519 |
|
|
write(v_log_line, string'("reading file : "));
|
520 |
|
|
write(v_log_line, file_name);
|
521 |
|
|
writeline(output, v_log_line);
|
522 |
|
|
proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); -- Open the file with data values for reading
|
523 |
|
|
LOOP
|
524 |
|
|
EXIT WHEN v_index = in_file_data'HIGH+1;
|
525 |
|
|
readline(v_in_file, v_input_line);
|
526 |
|
|
|
527 |
|
|
read(v_input_line, v_data(v_index,1)); -- real
|
528 |
|
|
read(v_input_line, v_comma);
|
529 |
|
|
|
530 |
|
|
read(v_input_line, v_data(v_index,2)); -- imag
|
531 |
|
|
v_index := v_index + 1;
|
532 |
|
|
END LOOP;
|
533 |
|
|
proc_common_close_file(v_file_status, v_in_file); -- Close the file
|
534 |
|
|
write(v_log_line, string'("finished reading file : "));
|
535 |
|
|
write(v_log_line, file_name);
|
536 |
|
|
writeline(output, v_log_line);
|
537 |
|
|
|
538 |
|
|
in_file_data <= v_data;
|
539 |
|
|
WAIT;
|
540 |
|
|
END proc_read_input_file;
|
541 |
|
|
|
542 |
|
|
|
543 |
|
|
------------------------------------------------------------------------------
|
544 |
|
|
-- PROCEDURE: Read the beamlet statistics memory into an matrix
|
545 |
|
|
------------------------------------------------------------------------------
|
546 |
|
|
|
547 |
|
|
PROCEDURE proc_fft_read_subband_statistics_memory(CONSTANT c_fft_lane : IN NATURAL;
|
548 |
|
|
CONSTANT c_fft : IN t_fft;
|
549 |
|
|
SIGNAL clk : IN STD_LOGIC;
|
550 |
|
|
SIGNAL mm_mosi : OUT t_mem_mosi;
|
551 |
|
|
SIGNAL mm_miso : IN t_mem_miso;
|
552 |
|
|
SIGNAL statistics_arr : OUT t_slv_64_arr) IS
|
553 |
|
|
VARIABLE v_offset : NATURAL;
|
554 |
|
|
VARIABLE v_nof_stats : NATURAL := c_fft.nof_points/c_fft.wb_factor;
|
555 |
|
|
VARIABLE v_statistics_arr : t_slv_64_arr(statistics_arr'RANGE);
|
556 |
|
|
BEGIN
|
557 |
|
|
v_offset := c_fft_lane*c_fft.stat_data_sz*v_nof_stats;
|
558 |
|
|
proc_read_subband_stats(v_nof_stats, v_offset, clk, mm_mosi, mm_miso, v_statistics_arr);
|
559 |
|
|
statistics_arr <= v_statistics_arr;
|
560 |
|
|
proc_common_wait_some_cycles(clk, 1); -- ensure that the last statistics_arr value gets assigned too
|
561 |
|
|
END proc_fft_read_subband_statistics_memory;
|
562 |
|
|
|
563 |
|
|
|
564 |
|
|
------------------------------------------------------------------------------
|
565 |
|
|
-- PROCEDURE: Reads the beamlet statistics into an array.
|
566 |
|
|
------------------------------------------------------------------------------
|
567 |
|
|
PROCEDURE proc_read_subband_stats( CONSTANT nof_subbands : IN NATURAL;
|
568 |
|
|
CONSTANT offset : IN NATURAL;
|
569 |
|
|
SIGNAL clk : IN STD_LOGIC;
|
570 |
|
|
SIGNAL mm_mosi : OUT t_mem_mosi;
|
571 |
|
|
SIGNAL mm_miso : IN t_mem_miso;
|
572 |
|
|
VARIABLE result : OUT t_slv_64_arr) IS
|
573 |
|
|
VARIABLE v_data_lo : STD_LOGIC_VECTOR(31 DOWNTO 0);
|
574 |
|
|
BEGIN
|
575 |
|
|
FOR J IN 0 TO nof_subbands-1 LOOP
|
576 |
|
|
-- Memory is 32-bit, therefor each power value (56-bit wide) must be composed out of two reads.
|
577 |
|
|
proc_mem_mm_bus_rd(offset+2*J, clk, mm_mosi);
|
578 |
|
|
proc_common_wait_some_cycles(clk, 1);
|
579 |
|
|
v_data_lo := mm_miso.rddata(31 DOWNTO 0);
|
580 |
|
|
proc_mem_mm_bus_rd(offset+2*J+1, clk, mm_mosi);
|
581 |
|
|
proc_common_wait_some_cycles(clk, 1);
|
582 |
|
|
result(J) := mm_miso.rddata(31 DOWNTO 0) & v_data_lo;
|
583 |
|
|
END LOOP;
|
584 |
|
|
END proc_read_subband_stats;
|
585 |
|
|
|
586 |
|
|
|
587 |
|
|
|
588 |
|
|
|
589 |
|
|
------------------------------------------------------------------------------
|
590 |
|
|
-- PROCEDURE: Prepare input array.
|
591 |
|
|
-- Combinatorial read data from source file and re-arrange in such
|
592 |
|
|
-- a way that it represents the data of one input stream
|
593 |
|
|
------------------------------------------------------------------------------
|
594 |
|
|
-- PROCEDURE proc_prepare_input_data( CONSTANT nof_subbands : IN NATURAL;
|
595 |
|
|
-- CONSTANT nof_inputs : IN NATURAL;
|
596 |
|
|
-- CONSTANT nof_input_streams : IN NATURAL;
|
597 |
|
|
-- CONSTANT input_stream_number : IN NATURAL;
|
598 |
|
|
-- VARIABLE re_arr : OUT t_integer_arr;
|
599 |
|
|
-- VARIABLE im_arr : OUT t_integer_arr;
|
600 |
|
|
-- file_name : IN STRING) IS
|
601 |
|
|
-- VARIABLE v_file_status : FILE_OPEN_STATUS;
|
602 |
|
|
-- FILE v_in_file : TEXT;
|
603 |
|
|
-- VARIABLE v_line : LINE;
|
604 |
|
|
-- VARIABLE v_in_temp : t_integer_arr(2*nof_inputs-1 downto 0);
|
605 |
|
|
-- CONSTANT c_nof_signal_inputs_per_input_stream : NATURAL := nof_inputs/nof_input_streams;
|
606 |
|
|
-- BEGIN
|
607 |
|
|
-- proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); -- Open the file with data values for reading
|
608 |
|
|
-- FOR I IN 0 TO nof_subbands-1 LOOP
|
609 |
|
|
-- proc_common_readline_file(v_file_status, v_in_file, v_in_temp, 2*nof_inputs); -- Read line with complex subband samples from all inputs
|
610 |
|
|
-- FOR J IN 0 TO c_nof_signal_inputs_per_input_stream-1 LOOP
|
611 |
|
|
-- re_arr(J*nof_subbands+I) := v_in_temp(2*(J+input_stream_number*c_nof_signal_inputs_per_input_stream));
|
612 |
|
|
-- im_arr(J*nof_subbands+I) := v_in_temp(2*(J+input_stream_number*c_nof_signal_inputs_per_input_stream)+1);
|
613 |
|
|
-- END LOOP;
|
614 |
|
|
-- END LOOP;
|
615 |
|
|
-- proc_common_close_file(v_file_status, v_in_file); -- Close the file
|
616 |
|
|
-- END proc_prepare_input_data;
|
617 |
|
|
|
618 |
|
|
END tb_fft_pkg;
|
619 |
|
|
|