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 3

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

powered by: WebSVN 2.1.0

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