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

Subversion Repositories astron_r2sdf_fft

[/] [astron_r2sdf_fft/] [trunk/] [tb_rTwoSDF.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: Raj Thilak Rajan : rajan at astron.nl: Nov 2009
2
--------------------------------------------------------------------------------
3
--
4
-- Copyright (C) 2012
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
--
24
-- Purpose: Test bench for the rTwoSDF pipelined radix 2 FFT
25
--
26
-- Description: ASTRON-RP-755
27
--   The testbench can simulate (via g_use_uniNoise_file):
28
--
29
--   a) complex uniform noise input from a file generated by testFFT_input.m
30
--   b) impulse input from a manually created file
31
--
32
--   Stimuli b) are useful for visual interpretation of the FFT output, because
33
--   an impulse at the real input and zero at the imaginary inpu will result
34
--   in DC and zero if the pulse occurs at the first sample or in sinus and
35
--   cosinus wave if the impulse occurs at a later sample. However because the
36
--   imaginary input is zero this does not cover all internals of the PFT 
37
--   implementation. Therefore stimuli a) are needed to fully verify the PFT.
38
--
39
--   The rTwoSDF output can be verified in two ways:
40
--
41
--   1) The MATLAB testFFT_output.m can calculate the floating point FFT and
42
--      compare it with the rTwoSDF implementation output file result.
43
--   2) The rTwoSDF implementation output file is also kept in SVN as golden
44
--      reference result to allow verification using a file diff command like
45
--      e.g. WinMerge. This then avoids the need to run MATLAB to verify.
46
--
47
--   The tb asserts an error when the output does not match the expected output
48
--   that is read from the golden reference file. The output is also written
49
--   to a default output file to support offline analysis.     
50
--
51
-- Usage:
52
--   > vsim -vopt -voptargs=+acc work.tb_rtwosdf (double click tb_rtwosdf icon)
53
--   > run -all
54
--   > observe the *_re and *_im as radix decimal, format analogue format
55
--     signals in the Wave window
56
--
57
-- Remarks:
58
-- . The tb uses LRM 1076-1987 style for file IO. This implies that only
59
--   simulator start and quit can open and close the file. The output file
60
--   can be read in a file editor, but the SVN file icon indicates that the
61
--   file is modified even if the contents is not changed. Only after closing
62
--   the simulation (> quit -sim) does the SVN file icon indicate the true
63
--   state. Next time we better use LRM 1076-1993 style for file IO.
64
 
65
library ieee, common_pkg_lib;
66
use IEEE.std_logic_1164.all;
67
use IEEE.numeric_std.all;
68
use IEEE.std_logic_textio.all;
69
use STD.textio.all;
70
use common_pkg_lib.common_pkg.all;
71
use common_pkg_lib.common_lfsr_sequences_pkg.all;
72
use common_pkg_lib.tb_common_pkg.all;
73
use work.rTwoSDFPkg.all;
74
use work.twiddlesPkg.all;
75
 
76
 
77
entity tb_rTwoSDF is
78
  generic(
79
    -- generics for tb
80
    g_use_uniNoise_file : boolean  := true;
81
    g_in_en             : natural  := 1;     -- 1 = always active, others = random control
82
    -- generics for rTwoSDF
83
    g_use_reorder       : boolean  := false;  -- tb supports both true and false
84
    g_nof_points        : natural  := 1024;
85
    g_in_dat_w          : natural  := 8;
86
    g_out_dat_w         : natural  := 14;
87
    g_guard_w           : natural  := 2      -- guard bits are used to avoid overflow in single FFT stage.
88
  );
89
end entity tb_rTwoSDF;
90
 
91
 
92
architecture tb of tb_rTwoSDF is
93
 
94
  constant c_clk_period : time    := 20 ns;
95
 
96
  constant c_nof_points_w : natural := ceil_log2(g_nof_points);
97
 
98
  -- input/output data width
99
  constant c_stage_dat_w : natural := sel_a_b(g_out_dat_w > c_dsp_mult_w, g_out_dat_w, c_dsp_mult_w); -- number of bits used between the stages
100
 
101
  -- input/output files
102
  constant c_file_len   : natural := 8*g_nof_points;
103
  constant c_repeat     : natural := 2;  -- >= 2 to have sufficent frames for c_outputFile evaluation by testFFT_output.m
104
 
105
  -- input from uniform noise file created automatically by MATLAB testFFT_input.m
106
  constant c_noiseInputFile    : string := "data/test/in/uniNoise_p"  & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w) &"_in.txt";
107
  constant c_noiseGoldenFile   : string := "data/test/out/uniNoise_p" & natural'image(g_nof_points)& "_in"& natural'image(g_in_dat_w) &"_out"&natural'image(g_out_dat_w) &"_out.txt";
108
  constant c_noiseOutputFile   : string := "data/test/out/uniNoise_out.txt";
109
 
110
  -- input from manually created file
111
  constant c_impulseInputFile  : string := "data/test/in/impulse_p"   & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w)& "_in.txt";
112
  constant c_impulseGoldenFile : string := "data/test/out/impulse_p"  & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w)& "_out.txt";
113
  constant c_impulseOutputFile : string := "data/test/out/impulse_out.txt";
114
 
115
  -- determine active stimuli and result files
116
  constant c_inputFile  : string := sel_a_b(g_use_uniNoise_file, c_noiseInputFile,  c_impulseInputFile);
117
  constant c_goldenFile : string := sel_a_b(g_use_uniNoise_file, c_noiseGoldenFile, c_impulseGoldenFile);
118
  constant c_outputFile : string := sel_a_b(g_use_uniNoise_file, c_noiseOutputFile, c_impulseOutputFile);
119
 
120
  -- signal definitions
121
  signal tb_end         : std_logic := '0';
122
  signal clk            : std_logic := '0';
123
  signal rst            : std_logic := '0';
124
  signal enable         : std_logic := '1';
125
  signal random         : std_logic_vector(15 downto 0) := (others=>'0');  -- use different lengths to have different random sequences
126
  signal in_en          : std_logic := '0';
127
 
128
  signal in_re          : std_logic_vector(g_in_dat_w-1 downto 0);
129
  signal in_im          : std_logic_vector(g_in_dat_w-1 downto 0);
130
  signal in_sync        : std_logic:= '0';
131
  signal in_val         : std_logic:= '0';
132
 
133
  signal out_re         : std_logic_vector(g_out_dat_w-1 downto 0);
134
  signal out_im         : std_logic_vector(g_out_dat_w-1 downto 0);
135
  signal out_sync       : std_logic:= '0';
136
  signal out_val        : std_logic:= '0';
137
 
138
  signal in_file_data   : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0));  -- [re, im]
139
  signal in_file_sync   : std_logic_vector(0 to c_file_len-1):= (others=>'0');
140
  signal in_file_val    : std_logic_vector(0 to c_file_len-1):= (others=>'0');
141
 
142
  signal in_index       : natural := 0;
143
  signal in_repeat      : natural := 0;
144
 
145
  signal gold_file_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0));  -- [re, im]
146
  signal gold_file_sync : std_logic_vector(0 to c_file_len-1):= (others=>'0');
147
  signal gold_file_val  : std_logic_vector(0 to c_file_len-1):= (others=>'0');
148
 
149
  signal gold_index_max : natural := c_file_len - 2*g_nof_points;
150
  signal gold_index     : natural;
151
  signal flip_index     : natural;
152
  signal gold_sync      : std_logic;
153
  signal gold_re        : integer;
154
  signal gold_im        : integer;
155
 
156
begin
157
 
158
  clk <= (not clk) or tb_end after c_clk_period/2;
159
  rst <= '1', '0' after c_clk_period*7;
160
  enable <= '0', '1' after c_clk_period*23;
161
  random <= func_common_random(random) when rising_edge(clk);
162
  in_en <= '1' when g_in_en=1 else random(random'HIGH);
163
 
164
 
165
  p_read_input_file : process
166
    file v_input : TEXT open READ_MODE is c_inputFile;  -- this is LRM 1076-1987 style and implies that only simulator start and quit can open and close the file
167
    variable v_log_line    : LINE;
168
    variable v_input_line  : LINE;
169
    variable v_index       : integer :=0;
170
    variable v_comma       : character;
171
    variable v_sync        : std_logic_vector(0 to c_file_len-1):=(others=>'0');
172
    variable v_val         : std_logic_vector(0 to c_file_len-1):=(others=>'0');
173
    variable v_data        : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0));
174
  begin
175
    -- wait 1 clock cycle to avoid that the output messages in the transcript window get lost in the 0 ps start up messages 
176
    proc_common_wait_some_cycles(clk, 1);
177
    -- combinatorially read the file into the array
178
    write(v_log_line, string'("reading stimuli file : "));
179
    write(v_log_line, c_inputFile);
180
    writeline(output, v_log_line);
181
    loop
182
      exit when endfile(v_input);
183
      readline(v_input, v_input_line);
184
 
185
      read(v_input_line, v_sync(v_index));    -- sync
186
      read(v_input_line, v_comma);
187
 
188
      read(v_input_line, v_val(v_index));     -- valid
189
      read(v_input_line, v_comma);
190
 
191
      read(v_input_line, v_data(v_index,1));  -- real
192
      read(v_input_line, v_comma);
193
 
194
      read(v_input_line, v_data(v_index,2));  -- imag
195
      v_index := v_index + 1;
196
    end loop;
197
    write(v_log_line, string'("finished reading stimuli file"));
198
    writeline(output, v_log_line);
199
 
200
    in_file_data <= v_data;
201
    in_file_sync <= v_sync;
202
    in_file_val  <= v_val;
203
    wait;
204
  end process;
205
 
206
  p_in_stimuli : process(clk, rst)
207
  begin
208
    if rst='1' then
209
      in_re   <= (others=>'0');
210
      in_im   <= (others=>'0');
211
      in_sync <= '0';
212
      in_val  <= '0';
213
 
214
      in_index  <=  0;
215
      in_repeat <=  0;
216
    elsif rising_edge(clk) then
217
 
218
      in_sync <= '0';
219
      in_val  <= '0';
220
 
221
      -- start stimuli some arbitrary time after rst release to ensure that the proper behaviour of the DUT does not depend on that time
222
      if enable='1' then
223
        -- use always active input (the in_file contents may still contain blocks with in_val='0') or use random active input
224
        if in_en='1' then
225
          if in_index<c_file_len-1 then
226
            in_index <= in_index+1;
227
          else
228
            in_index <= 0;
229
            in_repeat <= in_repeat + 1;
230
          end if;
231
 
232
          if in_repeat < c_repeat then
233
            in_re   <= std_logic_vector(to_signed(in_file_data(in_index, 1), g_in_dat_w));
234
            in_im   <= std_logic_vector(to_signed(in_file_data(in_index, 2), g_in_dat_w));
235
            in_sync <= std_logic(in_file_sync(in_index));
236
            in_val  <= std_logic(in_file_val(in_index));
237
          end if;
238
 
239
          if in_repeat > c_repeat then
240
            tb_end <= '1';
241
          end if;
242
        end if;
243
      end if;
244
 
245
    end if;
246
  end process;
247
 
248
  -- DUT = Device Under Test
249
  u_rTwoSDF : entity work.rTwoSDF
250
  generic map(
251
    -- generics for the FFT
252
    g_use_reorder => g_use_reorder,
253
    g_in_dat_w    => g_in_dat_w,
254
    g_out_dat_w   => g_out_dat_w,
255
    g_stage_dat_w => c_stage_dat_w,
256
    g_guard_w     => g_guard_w,
257
    g_nof_points  => g_nof_points
258
  )
259
  port map(
260
    clk       => clk,
261
    rst       => rst,
262
    in_re     => in_re,
263
    in_im     => in_im,
264
    in_val    => in_val,
265
    out_re    => out_re,
266
    out_im    => out_im,
267
    out_val   => out_val
268
  );
269
 
270
  -- Read golden file with the expected DUT output
271
  p_read_golden_file : process
272
    file v_golden : TEXT open READ_MODE is c_goldenFile;  -- this is LRM 1076-1987 style and implies that only simulator start and quit can open and close the file
273
    variable v_log_line    : LINE;
274
    variable v_golden_line : LINE;
275
    variable v_index       : integer :=0;
276
    variable v_comma       : character;
277
    variable v_sync        : std_logic_vector(0 to c_file_len-1):=(others=>'0');
278
    variable v_val         : std_logic_vector(0 to c_file_len-1):=(others=>'0');
279
    variable v_data        : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0));
280
  begin
281
    -- wait 1 clock cycle to avoid that the output messages in the transcript window get lost in the 0 ps start up messages 
282
    proc_common_wait_some_cycles(clk, 1);
283
    -- combinatorially read the file into the array
284
    write(v_log_line, string'("reading golden file : "));
285
    write(v_log_line, c_goldenFile);
286
    writeline(output, v_log_line);
287
    loop
288
      exit when endfile(v_golden);
289
      readline(v_golden, v_golden_line);
290
 
291
      read(v_golden_line, v_sync(v_index));    -- sync
292
      read(v_golden_line, v_comma);
293
 
294
      read(v_golden_line, v_val(v_index));     -- valid
295
      read(v_golden_line, v_comma);
296
 
297
      read(v_golden_line, v_data(v_index,1));  -- real
298
      read(v_golden_line, v_comma);
299
 
300
      read(v_golden_line, v_data(v_index,2));  -- imag
301
      v_index := v_index + 1;
302
    end loop;
303
    write(v_log_line, string'("finished reading golden file"));
304
    writeline(output, v_log_line);
305
 
306
    gold_file_data <= v_data;
307
    gold_file_sync <= v_sync;
308
    gold_file_val  <= v_val;
309
    wait;
310
  end process;
311
 
312
  -- Show read data in Wave Window for debug purposes
313
  gold_index <= gold_index + 1 when rising_edge(clk) and out_val='1';
314
  flip_index <= (gold_index / g_nof_points) * g_nof_points + flip(gold_index mod g_nof_points, c_nof_points_w);
315
  gold_sync  <= gold_file_sync(gold_index);
316
  gold_re    <= gold_file_data(gold_index,1) when g_use_reorder=true else gold_file_data(flip_index,1);
317
  gold_im    <= gold_file_data(gold_index,2) when g_use_reorder=true else gold_file_data(flip_index,2);
318
 
319
  -- Verify the output of the DUT with the expected output from the golden reference file
320
  p_verify_output : process(clk)
321
  begin
322
    -- Compare
323
    if rising_edge(clk) then
324
      if out_val='1' and gold_index <= gold_index_max then
325
        -- only write when out_val='1', because then the file is independent of cycles with invalid out_dat
326
        assert out_sync        = gold_sync report "Output sync error"      severity error;
327
        assert TO_SINT(out_re) = gold_re   report "Output real data error" severity error;
328
        assert TO_SINT(out_im) = gold_im   report "Output imag data error" severity error;
329
      end if;
330
    end if;
331
  end process;
332
 
333
  -- Write to default output file, this allows using command line diff or graphical diff viewer to compare it with the golden result file
334
  p_write_output_file : process(clk)
335
    file     v_output : TEXT open WRITE_MODE is c_outputFile;  -- this is LRM 1076-1987 style and implies that only simulator start and quit can open and close the file
336
    variable v_line   : LINE;
337
  begin
338
    if rising_edge(clk) then
339
      if out_val='1' then
340
        -- only write when out_val='1', because then the file is independent of cycles with invalid out_dat
341
        write(v_line, out_sync);
342
        write(v_line, string'(","));
343
        write(v_line, out_val);
344
        write(v_line, string'(","));
345
        write(v_line, to_integer(signed(out_re)));
346
        write(v_line, string'(","));
347
        write(v_line, to_integer(signed(out_im)));
348
        writeline(v_output, v_line);
349
      end if;
350
    end if;
351
  end process;
352
 
353
end tb;

powered by: WebSVN 2.1.0

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