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

Subversion Repositories astron_wb_fft

[/] [astron_wb_fft/] [trunk/] [tb_fft_r2_par.vhd] - Blame information for rev 3

Go to most recent revision | 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
--
21
-- Purpose: Test bench for fft_r2_par.vhd using file data
22
--
23
-- Usage:
24
--   This tb uses the same Matlab stimuli and expected results as
25
--   tb_fft_r2_pipe.vhd.
26
--
27
--   For the fft_r2_par nof_chan=0, because with parallel input the time
28
--   multiplexed channels can be applied completely outside the FFT. I.e first
29
--   input block with g_fft.nof_points time samples in parallel for channel 0,
30
--   then idem for the next channel etc.
31
--   For the fft_r2_par wb_factor wb_factor=nof_points effectively, because
32
--   the parallel FFT is parallel for the entire g_fft.nof_points input time
33
--   samples. More parallel then that is not possible.
34
--   The fft_r2_par does support use_reorder.
35
--   The fft_r2_par does support use_separate.
36
--   The fft_r2_par does support input flow control with invalid gaps in the
37
--   input.
38
--
39
--   For more description see tb_fft_r2_pipe.vhd.
40
--
41
--   > run -all
42
--   > testbench is selftesting.
43
--   > observe the *_scope signals as radix decimal, format analogue format
44
--     signals in the Wave window
45
--
46
-- Remark:
47
-- . The verification replays the captured parallel data to be able to display
48
--   it using the scope signals in the Wave window and to be able to reuse the
49
--   serial proc_fft_out_control() procedure for determining the exepected
50
--   order of the output data.
51
-- . In retrospect the verification could have been done without the replay by
52
--   using wb_factor=nof_points.
53
-- . Use separate dut_clk and tb_clk (both directly related to clk), to be
54
--   able to disable the dut_clk during verification to significantly speed
55
--   up the simulation.
56
library ieee, common_pkg_lib, rTwoSDF_lib, common_ram_lib, mm_lib;
57
use IEEE.std_logic_1164.all;
58
use IEEE.numeric_std.all;
59
use IEEE.std_logic_textio.all;
60
use std.textio.all;
61
use common_pkg_lib.common_pkg.all;
62
use common_ram_lib.common_ram_pkg.ALL;
63
use common_pkg_lib.common_lfsr_sequences_pkg.ALL;
64
use common_pkg_lib.tb_common_pkg.all;
65
use mm_lib.tb_common_mem_pkg.ALL;
66
use rTwoSDF_lib.rTwoSDFPkg.all;
67
use work.fft_pkg.all;
68
use work.tb_fft_pkg.all;
69
 
70
entity tb_fft_r2_par is
71
  generic(
72
    -- DUT generics
73
    --g_fft : t_fft := ( true, false,  true, 0, 1, 0, 128, 8, 16, 0, c_dsp_mult_w, 2, true, 56, 2);         -- two real inputs A and B
74
    g_fft : t_fft := ( true, false,  true, 0, 1, 0,  32, 8, 16, 0, c_dsp_mult_w, 2, true, 56, 2);         -- two real inputs A and B
75
    --g_fft : t_fft := ( true, false, false, 0, 1, 0,  64, 8, 16, 0, c_dsp_mult_w, 2, true, 56, 2);         -- complex input reordered
76
    --g_fft : t_fft := (false, false, false, 0, 1, 0,  64, 8, 16, 0, c_dsp_mult_w, 2, true, 56, 2);         -- complex input flipped
77
    --  type t_rtwo_fft is record
78
    --    use_reorder    : boolean;  -- = false for bit-reversed output, true for normal output
79
    --    use_fft_shift  : boolean;  -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
80
    --    use_separate   : boolean;  -- = false for complex input, true for two real inputs
81
    --    nof_chan       : natural;  -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan         
82
    --    wb_factor      : natural;  -- = default 1, wideband factor
83
    --    twiddle_offset : natural;  -- = default 0, twiddle offset for PFT sections in a wideband FFT
84
    --    nof_points     : natural;  -- = 1024, N point FFT
85
    --    in_dat_w       : natural;  -- = 8, number of input bits
86
    --    out_dat_w      : natural;  -- = 13, number of output bits, bit growth: in_dat_w + natural((ceil_log2(nof_points))/2 + 2)  
87
    --    out_gain_w     : natural;  -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
88
    --    stage_dat_w    : natural;  -- = 18, data width used between the stages(= DSP multiplier-width)
89
    --    guard_w        : natural;  -- = 2,  Guard used to avoid overflow in FFT stage. 
90
    --    guard_enable   : boolean;  -- = true when input needs guarding, false when input requires no guarding but scaling must be skipped at the last stage(s) (used in wb fft)
91
    --    stat_data_w    : positive; -- = 56 (= 18b+18b)+log2(781250)
92
    --    stat_data_sz   : positive; -- = 2 (complex re and im)
93
    --  end record;
94
    --
95
    -- TB generics
96
    g_diff_margin           : integer := 2;  -- maximum difference between HDL output and expected output (> 0 to allow minor rounding differences)
97
 
98
    -- Two real input data files A and B used when g_fft.use_separate = true
99
    --g_data_file_a           : string := "data/run_pfft_m_sinusoid_chirp_8b_128points_16b.dat";
100
    --g_data_file_a_nof_lines : natural := 25600;
101
    --g_data_file_b           : string := "data/run_pfft_m_impulse_chirp_8b_128points_16b.dat";
102
    --g_data_file_b_nof_lines : natural := 25600;
103
 
104
    g_data_file_a           : string := "data/run_pfft_m_sinusoid_8b_32points_16b.dat";
105
    g_data_file_a_nof_lines : natural := 160;
106
    g_data_file_b           : string := "UNUSED";
107
    g_data_file_b_nof_lines : natural := 0;
108
 
109
    -- One complex input data file C used when g_fft.use_separate = false
110
    --g_data_file_c           : string := "data/run_pfft_complex_m_phasor_chirp_8b_64points_16b.dat";
111
    --g_data_file_c_nof_lines : natural := 12800;
112
    g_data_file_c           : string := "data/run_pfft_complex_m_phasor_8b_64points_16b.dat";
113
    g_data_file_c_nof_lines : natural := 320;
114
 
115
    g_data_file_nof_lines   : natural := 160;
116
    g_enable_in_val_gaps    : boolean := FALSE   -- when false then in_val flow control active continuously, else with random inactive gaps
117
  );
118
end entity tb_fft_r2_par;
119
 
120
architecture tb of tb_fft_r2_par is
121
 
122
  constant c_clk_period            : time := 10 ns;
123
 
124
  constant c_in_complex            : boolean := not g_fft.use_separate;
125
  constant c_fft_r2_check          : boolean := fft_r2_parameter_asserts(g_fft);
126
 
127
  constant c_nof_channels          : natural := 1;  -- fixed g_fft.nof_chan=0, because the concept of channels is void for the parallel FFT
128
 
129
  constant c_rnd_factor            : natural := sel_a_b(g_enable_in_val_gaps, 3, 1);
130
  constant c_dut_block_latency     : natural := 3;
131
  constant c_dut_clk_latency       : natural := g_fft.nof_points * c_dut_block_latency * c_rnd_factor;  -- worst case
132
                                                -- need to account for g_fft.nof_points, because tb verifies on serialized output
133
 
134
  -- input/output data width
135
  constant c_in_dat_w              : natural := g_fft.in_dat_w;
136
  constant c_out_dat_w             : natural := g_fft.out_dat_w;
137
 
138
  -- Data file access
139
  constant c_nof_lines_header        : natural := 2;
140
  constant c_nof_lines_a_wg_dat      : natural := g_data_file_a_nof_lines;                    -- Real input A via in_re, one value per line
141
  constant c_nof_lines_a_pfft_dat    : natural := g_data_file_a_nof_lines/c_nof_complex;      -- Half spectrum, two values per line (re, im)
142
  constant c_nof_lines_a_pfft_header : natural := c_nof_lines_header + c_nof_lines_a_wg_dat;
143
  constant c_nof_lines_b_wg_dat      : natural := g_data_file_b_nof_lines;                    -- Real input B via in_im, one value per line
144
  constant c_nof_lines_b_pfft_dat    : natural := g_data_file_b_nof_lines/c_nof_complex;      -- Half spectrum, two values per line (re, im)
145
  constant c_nof_lines_b_pfft_header : natural := c_nof_lines_header + c_nof_lines_b_wg_dat;
146
  constant c_nof_lines_c_wg_dat      : natural := g_data_file_c_nof_lines;                    -- Complex input, two values per line (re, im)
147
  constant c_nof_lines_c_pfft_dat    : natural := g_data_file_c_nof_lines;                    -- Full spectrum, two values per line (re, im)
148
  constant c_nof_lines_c_pfft_header : natural := c_nof_lines_header + c_nof_lines_c_wg_dat;
149
 
150
  constant c_gap_factor            : natural := sel_a_b(g_enable_in_val_gaps, 3, 1);
151
 
152
  -- signal definitions
153
  signal tb_end                 : std_logic := '0';
154
  signal tb_end_dut             : std_logic := '0';
155
  signal clk                    : std_logic := '0';
156
  signal dut_clk                : std_logic := '0';
157
  signal tb_clk                 : std_logic := '0';
158
  signal rst                    : std_logic := '0';
159
  signal random                 : std_logic_vector(15 DOWNTO 0) := (OTHERS=>'0');  -- use different lengths to have different random sequences
160
 
161
  signal input_data_a_arr       : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- one value per line (A via re input)
162
  signal input_data_b_arr       : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- one value per line (B via im input)
163
  signal input_data_c_arr       : t_integer_arr(0 to g_data_file_nof_lines*c_nof_complex-1) := (OTHERS=>0);  -- two values per line (re, im)
164
 
165
  signal output_data_a_re_arr   : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, re
166
  signal output_data_a_im_arr   : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, im
167
  signal output_data_b_re_arr   : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, re
168
  signal output_data_b_im_arr   : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, im
169
  signal output_data_c_re_arr   : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- full spectrum, re
170
  signal output_data_c_im_arr   : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- full spectrum, im  
171
 
172
  signal expected_data_a_arr    : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- half spectrum, two values per line (re, im)
173
  signal expected_data_a_re_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, re
174
  signal expected_data_a_im_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, im
175
  signal expected_data_b_arr    : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- half spectrum, two values per line (re, im)
176
  signal expected_data_b_re_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, re
177
  signal expected_data_b_im_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0);  -- half spectrum, im
178
  signal expected_data_c_arr    : t_integer_arr(0 to g_data_file_nof_lines*c_nof_complex-1) := (OTHERS=>0);  -- full spectrum, two values per line (re, im)
179
  signal expected_data_c_re_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- full spectrum, re
180
  signal expected_data_c_im_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0);                -- full spectrum, im  
181
 
182
  signal t_blk                  : integer := 0;  -- block time counter
183
 
184
  -- Input
185
  signal in_dat_a               : std_logic_vector(c_in_dat_w-1 downto 0);
186
  signal in_dat_a_scope         : integer;
187
  signal in_dat_b               : std_logic_vector(c_in_dat_w-1 downto 0);
188
  signal in_dat_b_scope         : integer;
189
  signal in_val_ab              : std_logic:= '0';
190
  signal in_re_arr              : t_fft_slv_arr(g_fft.nof_points-1 downto 0);
191
  signal in_im_arr              : t_fft_slv_arr(g_fft.nof_points-1 downto 0);
192
  signal in_val                 : std_logic:= '0';
193
  signal in_val_cnt             : natural := 0;
194
  signal in_gap                 : std_logic := '0';
195
 
196
  -- Output control
197
 
198
  signal out_re_arr             : t_fft_slv_arr(g_fft.nof_points-1 downto 0);
199
  signal out_im_arr             : t_fft_slv_arr(g_fft.nof_points-1 downto 0);
200
  signal out_val                : std_logic:= '0';  -- for parallel output
201
  signal out_val_cnt            : natural := 0;
202
  signal out_channel            : natural := 0;     -- not used for parallel FFT, set at default 0
203
  signal out_val_a              : std_logic:= '0';  -- for real A
204
  signal out_val_b              : std_logic:= '0';  -- for real B
205
  signal out_val_c              : std_logic:= '0';  -- for complex(A,B)
206
  signal out_cnt                : natural := 0;
207
  signal out_bin_cnt            : natural := 0;
208
  signal out_bin                : natural;
209
 
210
  -- Output data
211
  signal out_re                 : std_logic_vector(c_out_dat_w-1 downto 0);
212
  signal out_im                 : std_logic_vector(c_out_dat_w-1 downto 0);
213
 
214
  -- Output data for complex input data
215
  signal out_re_c_scope         : integer := 0;
216
  signal exp_re_c_scope         : integer := 0;
217
  signal out_im_c_scope         : integer := 0;
218
  signal exp_im_c_scope         : integer := 0;
219
 
220
  signal diff_re_c_scope        : integer := 0;
221
  signal diff_im_c_scope        : integer := 0;
222
 
223
  -- register control signals to account for clk register in output scope signals
224
  signal reg_out_val_a          : std_logic := '0';
225
  signal reg_out_val_b          : std_logic := '0';
226
  signal reg_out_val_c          : std_logic := '0';
227
  signal reg_out_bin_cnt        : natural := 0;
228
  signal reg_out_bin            : natural;
229
 
230
  -- Output data two real input data A and B
231
  signal out_re_a_scope         : integer := 0;
232
  signal exp_re_a_scope         : integer := 0;
233
  signal out_im_a_scope         : integer := 0;
234
  signal exp_im_a_scope         : integer := 0;
235
 
236
  signal out_re_b_scope         : integer := 0;
237
  signal exp_re_b_scope         : integer := 0;
238
  signal out_im_b_scope         : integer := 0;
239
  signal exp_im_b_scope         : integer := 0;
240
 
241
  signal diff_re_a_scope        : integer := 0;
242
  signal diff_im_a_scope        : integer := 0;
243
  signal diff_re_b_scope        : integer := 0;
244
  signal diff_im_b_scope        : integer := 0;
245
 
246
begin
247
 
248
  clk <= (not clk) or tb_end after c_clk_period/2;
249
  dut_clk <= clk or tb_end_dut;
250
  tb_clk <= clk and tb_end_dut;
251
  rst <= '1', '0' after c_clk_period*7;
252
  random <= func_common_random(random) WHEN rising_edge(dut_clk);
253
  in_gap <= random(random'HIGH) WHEN g_enable_in_val_gaps=TRUE ELSE '0';
254
 
255
  ---------------------------------------------------------------
256
  -- DATA INPUT
257
  ---------------------------------------------------------------
258
  p_input_stimuli : process
259
    variable vP : natural;
260
  begin
261
    -- read input data from file
262
    if c_in_complex then
263
      proc_common_read_integer_file(g_data_file_c, c_nof_lines_header, g_data_file_nof_lines, c_nof_complex, input_data_c_arr);
264
    else
265
      proc_common_read_integer_file(g_data_file_a, c_nof_lines_header, g_data_file_nof_lines, 1, input_data_a_arr);
266
      proc_common_read_integer_file(g_data_file_b, c_nof_lines_header, g_data_file_nof_lines, 1, input_data_b_arr);
267
    end if;
268
    wait for 1 ns;
269
    in_re_arr <= (others=>(others=>'0'));
270
    in_im_arr <= (others=>(others=>'0'));
271
    in_val <= '0';
272
    proc_common_wait_until_low(dut_clk, rst);         -- Wait until reset has finished
273
    proc_common_wait_some_cycles(dut_clk, 10);        -- Wait an additional amount of cycles
274
 
275
    -- apply stimuli
276
    for B in 0 to g_data_file_nof_lines/g_fft.nof_points-1 loop  -- serial
277
      for I in 0 to g_fft.nof_points-1 loop  -- parallel
278
        if c_in_complex then
279
          in_re_arr(I) <= to_fft_svec(input_data_c_arr(2*(B*g_fft.nof_points+I)));
280
          in_im_arr(I) <= to_fft_svec(input_data_c_arr(2*(B*g_fft.nof_points+I)+1));
281
        else
282
          in_re_arr(I) <= to_fft_svec(input_data_a_arr(B*g_fft.nof_points+I));
283
          in_im_arr(I) <= to_fft_svec(input_data_b_arr(B*g_fft.nof_points+I));
284
        end if;
285
      end loop;
286
      in_val <= '1';
287
      proc_common_wait_some_cycles(dut_clk, 1);
288
      if in_gap='1' then
289
        in_val <= '0';
290
        proc_common_wait_some_cycles(dut_clk, 1);
291
      end if;
292
    end loop;
293
 
294
    -- Wait until done
295
    in_val <= '0';
296
    proc_common_wait_some_cycles(dut_clk, c_dut_clk_latency);  -- wait for DUT latency
297
    tb_end_dut <= '1';
298
    wait;
299
  end process;
300
 
301
  ---------------------------------------------------------------
302
  -- DUT = Device Under Test
303
  ---------------------------------------------------------------
304
  u_dut : entity work.fft_r2_par
305
  generic map(
306
    g_fft      => g_fft
307
  )
308
  port map(
309
    clk        => dut_clk,
310
    rst        => rst,
311
    in_re_arr  => in_re_arr,
312
    in_im_arr  => in_im_arr,
313
    in_val     => in_val,
314
    out_re_arr => out_re_arr,
315
    out_im_arr => out_im_arr,
316
    out_val    => out_val
317
  );
318
 
319
  -- Block count
320
  in_val_cnt  <= in_val_cnt+1  when rising_edge(dut_clk) and in_val='1'  else in_val_cnt;
321
  out_val_cnt <= out_val_cnt+1 when rising_edge(dut_clk) and out_val='1' else out_val_cnt;
322
 
323
  -- Block count t_blk
324
  t_blk <= in_val_cnt;
325
 
326
  -- Capture the output
327
  p_capture_output : process(dut_clk)
328
  begin
329
    if rising_edge(dut_clk) then
330
      if out_val='1' then
331
        if c_in_complex then
332
          for I in 0 to g_fft.nof_points-1 loop
333
            output_data_c_re_arr(out_val_cnt*g_fft.nof_points + I) <= TO_SINT(out_re_arr(I));
334
            output_data_c_im_arr(out_val_cnt*g_fft.nof_points + I) <= TO_SINT(out_im_arr(I));
335
          end loop;
336
        else
337
          for I in 0 to g_fft.nof_points/c_nof_complex-1 loop
338
            output_data_a_re_arr(out_val_cnt*g_fft.nof_points/c_nof_complex + I) <= TO_SINT(out_re_arr(2*I));
339
            output_data_a_im_arr(out_val_cnt*g_fft.nof_points/c_nof_complex + I) <= TO_SINT(out_im_arr(2*I));
340
            output_data_b_re_arr(out_val_cnt*g_fft.nof_points/c_nof_complex + I) <= TO_SINT(out_re_arr(2*I+1));
341
            output_data_b_im_arr(out_val_cnt*g_fft.nof_points/c_nof_complex + I) <= TO_SINT(out_im_arr(2*I+1));
342
          end loop;
343
        end if;
344
      end if;
345
    end if;
346
  end process;
347
 
348
  ---------------------------------------------------------------
349
  -- REPLAY INPUT AND CAPTURED OUTPUT SERIALLY
350
  ---------------------------------------------------------------
351
  p_pipe_input : process
352
  begin
353
    in_val_ab <= '0';
354
    -- Wait until tb_end_dut
355
    proc_common_wait_until_high(tb_clk, tb_end_dut);
356
 
357
    -- Show the input serially
358
    for B in 0 to g_data_file_nof_lines/g_fft.nof_points-1 loop  -- serial
359
      for I in 0 to g_fft.nof_points-1 loop  -- serial
360
        if c_in_complex then
361
          in_dat_a <= TO_SVEC(input_data_c_arr(2*(B*g_fft.nof_points+I)), c_in_dat_w);
362
          in_dat_b <= TO_SVEC(input_data_c_arr(2*(B*g_fft.nof_points+I)+1), c_in_dat_w);
363
        else
364
          in_dat_a <= TO_SVEC(input_data_a_arr(B*g_fft.nof_points+I), c_in_dat_w);
365
          in_dat_b <= TO_SVEC(input_data_b_arr(B*g_fft.nof_points+I), c_in_dat_w);
366
        end if;
367
        in_val_ab <= '1';
368
        proc_common_wait_some_cycles(tb_clk, 1);
369
      end loop;
370
    end loop;
371
    in_val_ab <= '0';
372
    wait;
373
  end process;
374
 
375
  p_pipe_output : process
376
  begin
377
    out_val_c <= '0';
378
    -- Wait until tb_end_dut
379
    proc_common_wait_until_high(tb_clk, tb_end_dut);
380
 
381
    -- Show the output serially
382
    for B in 0 to g_data_file_nof_lines/g_fft.nof_points-1 loop  -- serial
383
      for I in 0 to g_fft.nof_points-1 loop  -- serial
384
        if c_in_complex then
385
          out_re <= TO_SVEC(output_data_c_re_arr(B*g_fft.nof_points+I), c_out_dat_w);
386
          out_im <= TO_SVEC(output_data_c_im_arr(B*g_fft.nof_points+I), c_out_dat_w);
387
        else
388
          if I mod c_nof_complex = 0 then  -- must use I here, cannot use out_cnt because then for the first two out_val_c mod will yield 0
389
            out_re <= TO_SVEC(output_data_a_re_arr((B*g_fft.nof_points+I)/c_nof_complex), c_out_dat_w);
390
            out_im <= TO_SVEC(output_data_a_im_arr((B*g_fft.nof_points+I)/c_nof_complex), c_out_dat_w);
391
          else
392
            out_re <= TO_SVEC(output_data_b_re_arr((B*g_fft.nof_points+I)/c_nof_complex), c_out_dat_w);
393
            out_im <= TO_SVEC(output_data_b_im_arr((B*g_fft.nof_points+I)/c_nof_complex), c_out_dat_w);
394
          end if;
395
        end if;
396
        out_val_c <= '1';
397
        proc_common_wait_some_cycles(tb_clk, 1);
398
        --out_cnt <= out_cnt + 1;  -- can increment out_cnt here inside this process after rising_edge(tb_clk) or in separate concurrent process statement
399
      end loop;
400
    end loop;
401
    out_val_c <= '0';
402
 
403
    proc_common_wait_some_cycles(tb_clk, 100);
404
    tb_end <= '1';
405
    wait;
406
  end process;
407
 
408
  out_cnt <= out_cnt + 1 when rising_edge(tb_clk) and out_val_c='1' else out_cnt;
409
 
410
  proc_fft_out_control(1, g_fft.nof_points, c_nof_channels, g_fft.use_reorder, g_fft.use_fft_shift, g_fft.use_separate,
411
                       out_cnt, out_val_c, out_val_a, out_val_b, out_channel, out_bin, out_bin_cnt);
412
 
413
  ---------------------------------------------------------------
414
  -- VERIFY OUTPUT
415
  ---------------------------------------------------------------
416
  p_verify_out_val_cnt : process
417
  begin
418
    -- Wait until tb_end_dut
419
    proc_common_wait_until_high(tb_clk, tb_end_dut);
420
    assert in_val_cnt > 0           report "Test did not run, no valid input data"  severity error;
421
    assert out_val_cnt = in_val_cnt report "Unexpected number of valid output data" severity error;
422
    wait;
423
  end process;
424
 
425
  p_expected_output : process
426
  begin
427
    -- read expected output data from file
428
    if c_in_complex then
429
      proc_common_read_integer_file(g_data_file_c, c_nof_lines_c_pfft_header, g_data_file_nof_lines, c_nof_complex, expected_data_c_arr);
430
      wait for 1 ns;
431
      for I in 0 to g_data_file_nof_lines-1 loop
432
        expected_data_c_re_arr(I) <= expected_data_c_arr(2*I);
433
        expected_data_c_im_arr(I) <= expected_data_c_arr(2*I+1);
434
      end loop;
435
    else
436
      proc_common_read_integer_file(g_data_file_a, c_nof_lines_a_pfft_header, g_data_file_nof_lines/c_nof_complex, c_nof_complex, expected_data_a_arr);
437
      proc_common_read_integer_file(g_data_file_b, c_nof_lines_b_pfft_header, g_data_file_nof_lines/c_nof_complex, c_nof_complex, expected_data_b_arr);
438
      wait for 1 ns;
439
      for I in 0 to g_data_file_nof_lines/c_nof_complex-1 loop
440
        expected_data_a_re_arr(I) <= expected_data_a_arr(2*I);
441
        expected_data_a_im_arr(I) <= expected_data_a_arr(2*I+1);
442
        expected_data_b_re_arr(I) <= expected_data_b_arr(2*I);
443
        expected_data_b_im_arr(I) <= expected_data_b_arr(2*I+1);
444
      end loop;
445
    end if;
446
    wait;
447
  end process;
448
 
449
  -- p_verify_output
450
  gen_verify_two_real : if not c_in_complex generate
451
    assert diff_re_a_scope >= -g_diff_margin and diff_re_a_scope <= g_diff_margin report "Output data A real error" severity error;
452
    assert diff_im_a_scope >= -g_diff_margin and diff_im_a_scope <= g_diff_margin report "Output data A imag error" severity error;
453
    assert diff_re_b_scope >= -g_diff_margin and diff_re_b_scope <= g_diff_margin report "Output data B real error" severity error;
454
    assert diff_im_b_scope >= -g_diff_margin and diff_im_b_scope <= g_diff_margin report "Output data B imag error" severity error;
455
  end generate;
456
  gen_verify_complex : if c_in_complex generate
457
    assert diff_re_c_scope >= -g_diff_margin and diff_re_c_scope <= g_diff_margin report "Output data C real error" severity error;
458
    assert diff_im_c_scope >= -g_diff_margin and diff_im_c_scope <= g_diff_margin report "Output data C imag error" severity error;
459
  end generate;
460
 
461
  ---------------------------------------------------------------
462
  -- DATA SCOPES
463
  ---------------------------------------------------------------
464
  in_dat_a_scope <= TO_SINT(in_dat_a);
465
  in_dat_b_scope <= TO_SINT(in_dat_b);
466
 
467
  -- clk diff to avoid combinatorial glitches when selecting the data with out_val_a,b, out_val
468
  reg_out_val_a   <= out_val_a   when rising_edge(tb_clk);
469
  reg_out_val_b   <= out_val_b   when rising_edge(tb_clk);
470
  reg_out_val_c   <= out_val_c   when rising_edge(tb_clk);
471
  reg_out_bin_cnt <= out_bin_cnt when rising_edge(tb_clk);
472
  reg_out_bin     <= out_bin     when rising_edge(tb_clk);
473
 
474
  out_re_a_scope <= TO_SINT(out_re) when rising_edge(tb_clk) and out_val_a='1';
475
  out_im_a_scope <= TO_SINT(out_im) when rising_edge(tb_clk) and out_val_a='1';
476
  out_re_b_scope <= TO_SINT(out_re) when rising_edge(tb_clk) and out_val_b='1';
477
  out_im_b_scope <= TO_SINT(out_im) when rising_edge(tb_clk) and out_val_b='1';
478
  out_re_c_scope <= TO_SINT(out_re) when rising_edge(tb_clk) and out_val_c='1';
479
  out_im_c_scope <= TO_SINT(out_im) when rising_edge(tb_clk) and out_val_c='1';
480
 
481
  exp_re_a_scope <= expected_data_a_re_arr(out_bin_cnt) when rising_edge(tb_clk) and out_val_a='1';
482
  exp_im_a_scope <= expected_data_a_im_arr(out_bin_cnt) when rising_edge(tb_clk) and out_val_a='1';
483
  exp_re_b_scope <= expected_data_b_re_arr(out_bin_cnt) when rising_edge(tb_clk) and out_val_b='1';
484
  exp_im_b_scope <= expected_data_b_im_arr(out_bin_cnt) when rising_edge(tb_clk) and out_val_b='1';
485
  exp_re_c_scope <= expected_data_c_re_arr(out_bin_cnt) when rising_edge(tb_clk) and out_val_c='1';
486
  exp_im_c_scope <= expected_data_c_im_arr(out_bin_cnt) when rising_edge(tb_clk) and out_val_c='1';
487
 
488
  diff_re_a_scope <= exp_re_a_scope - out_re_a_scope;
489
  diff_im_a_scope <= exp_im_a_scope - out_im_a_scope;
490
  diff_re_b_scope <= exp_re_b_scope - out_re_b_scope;
491
  diff_im_b_scope <= exp_im_b_scope - out_im_b_scope;
492
  diff_re_c_scope <= exp_re_c_scope - out_re_c_scope;
493
  diff_im_c_scope <= exp_im_c_scope - out_im_c_scope;
494
 
495
end tb;

powered by: WebSVN 2.1.0

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