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 2

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

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

powered by: WebSVN 2.1.0

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