URL
https://opencores.org/ocsvn/astron_r2sdf_fft/astron_r2sdf_fft/trunk
Subversion Repositories astron_r2sdf_fft
[/] [astron_r2sdf_fft/] [trunk/] [tb_rTwoSDF.vhd] - Rev 2
Go to most recent revision | Compare with Previous | Blame | View Log
-- Author: Raj Thilak Rajan : rajan at astron.nl: Nov 2009 -------------------------------------------------------------------------------- -- -- Copyright (C) 2012 -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- -------------------------------------------------------------------------------- -- -- Purpose: Test bench for the rTwoSDF pipelined radix 2 FFT -- -- Description: ASTRON-RP-755 -- The testbench can simulate (via g_use_uniNoise_file): -- -- a) complex uniform noise input from a file generated by testFFT_input.m -- b) impulse input from a manually created file -- -- Stimuli b) are useful for visual interpretation of the FFT output, because -- an impulse at the real input and zero at the imaginary inpu will result -- in DC and zero if the pulse occurs at the first sample or in sinus and -- cosinus wave if the impulse occurs at a later sample. However because the -- imaginary input is zero this does not cover all internals of the PFT -- implementation. Therefore stimuli a) are needed to fully verify the PFT. -- -- The rTwoSDF output can be verified in two ways: -- -- 1) The MATLAB testFFT_output.m can calculate the floating point FFT and -- compare it with the rTwoSDF implementation output file result. -- 2) The rTwoSDF implementation output file is also kept in SVN as golden -- reference result to allow verification using a file diff command like -- e.g. WinMerge. This then avoids the need to run MATLAB to verify. -- -- The tb asserts an error when the output does not match the expected output -- that is read from the golden reference file. The output is also written -- to a default output file to support offline analysis. -- -- Usage: -- > vsim -vopt -voptargs=+acc work.tb_rtwosdf (double click tb_rtwosdf icon) -- > run -all -- > observe the *_re and *_im as radix decimal, format analogue format -- signals in the Wave window -- -- Remarks: -- . The tb uses LRM 1076-1987 style for file IO. This implies that only -- simulator start and quit can open and close the file. The output file -- can be read in a file editor, but the SVN file icon indicates that the -- file is modified even if the contents is not changed. Only after closing -- the simulation (> quit -sim) does the SVN file icon indicate the true -- state. Next time we better use LRM 1076-1993 style for file IO. library ieee, common_pkg_lib; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use IEEE.std_logic_textio.all; use STD.textio.all; use common_pkg_lib.common_pkg.all; use common_pkg_lib.common_lfsr_sequences_pkg.all; use common_pkg_lib.tb_common_pkg.all; use work.rTwoSDFPkg.all; use work.twiddlesPkg.all; entity tb_rTwoSDF is generic( -- generics for tb g_use_uniNoise_file : boolean := true; g_in_en : natural := 1; -- 1 = always active, others = random control -- generics for rTwoSDF g_use_reorder : boolean := false; -- tb supports both true and false g_nof_points : natural := 1024; g_in_dat_w : natural := 8; g_out_dat_w : natural := 14; g_guard_w : natural := 2 -- guard bits are used to avoid overflow in single FFT stage. ); end entity tb_rTwoSDF; architecture tb of tb_rTwoSDF is constant c_clk_period : time := 20 ns; constant c_nof_points_w : natural := ceil_log2(g_nof_points); -- input/output data width 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 -- input/output files constant c_file_len : natural := 8*g_nof_points; constant c_repeat : natural := 2; -- >= 2 to have sufficent frames for c_outputFile evaluation by testFFT_output.m -- input from uniform noise file created automatically by MATLAB testFFT_input.m constant c_noiseInputFile : string := "data/test/in/uniNoise_p" & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w) &"_in.txt"; 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"; constant c_noiseOutputFile : string := "data/test/out/uniNoise_out.txt"; -- input from manually created file constant c_impulseInputFile : string := "data/test/in/impulse_p" & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w)& "_in.txt"; constant c_impulseGoldenFile : string := "data/test/out/impulse_p" & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w)& "_out.txt"; constant c_impulseOutputFile : string := "data/test/out/impulse_out.txt"; -- determine active stimuli and result files constant c_inputFile : string := sel_a_b(g_use_uniNoise_file, c_noiseInputFile, c_impulseInputFile); constant c_goldenFile : string := sel_a_b(g_use_uniNoise_file, c_noiseGoldenFile, c_impulseGoldenFile); constant c_outputFile : string := sel_a_b(g_use_uniNoise_file, c_noiseOutputFile, c_impulseOutputFile); -- signal definitions signal tb_end : std_logic := '0'; signal clk : std_logic := '0'; signal rst : std_logic := '0'; signal enable : std_logic := '1'; signal random : std_logic_vector(15 downto 0) := (others=>'0'); -- use different lengths to have different random sequences signal in_en : std_logic := '0'; signal in_re : std_logic_vector(g_in_dat_w-1 downto 0); signal in_im : std_logic_vector(g_in_dat_w-1 downto 0); signal in_sync : std_logic:= '0'; signal in_val : std_logic:= '0'; signal out_re : std_logic_vector(g_out_dat_w-1 downto 0); signal out_im : std_logic_vector(g_out_dat_w-1 downto 0); signal out_sync : std_logic:= '0'; signal out_val : std_logic:= '0'; signal in_file_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0)); -- [re, im] signal in_file_sync : std_logic_vector(0 to c_file_len-1):= (others=>'0'); signal in_file_val : std_logic_vector(0 to c_file_len-1):= (others=>'0'); signal in_index : natural := 0; signal in_repeat : natural := 0; signal gold_file_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0)); -- [re, im] signal gold_file_sync : std_logic_vector(0 to c_file_len-1):= (others=>'0'); signal gold_file_val : std_logic_vector(0 to c_file_len-1):= (others=>'0'); signal gold_index_max : natural := c_file_len - 2*g_nof_points; signal gold_index : natural; signal flip_index : natural; signal gold_sync : std_logic; signal gold_re : integer; signal gold_im : integer; begin clk <= (not clk) or tb_end after c_clk_period/2; rst <= '1', '0' after c_clk_period*7; enable <= '0', '1' after c_clk_period*23; random <= func_common_random(random) when rising_edge(clk); in_en <= '1' when g_in_en=1 else random(random'HIGH); p_read_input_file : process 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 variable v_log_line : LINE; variable v_input_line : LINE; variable v_index : integer :=0; variable v_comma : character; variable v_sync : std_logic_vector(0 to c_file_len-1):=(others=>'0'); variable v_val : std_logic_vector(0 to c_file_len-1):=(others=>'0'); variable v_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0)); begin -- wait 1 clock cycle to avoid that the output messages in the transcript window get lost in the 0 ps start up messages proc_common_wait_some_cycles(clk, 1); -- combinatorially read the file into the array write(v_log_line, string'("reading stimuli file : ")); write(v_log_line, c_inputFile); writeline(output, v_log_line); loop exit when endfile(v_input); readline(v_input, v_input_line); read(v_input_line, v_sync(v_index)); -- sync read(v_input_line, v_comma); read(v_input_line, v_val(v_index)); -- valid read(v_input_line, v_comma); read(v_input_line, v_data(v_index,1)); -- real read(v_input_line, v_comma); read(v_input_line, v_data(v_index,2)); -- imag v_index := v_index + 1; end loop; write(v_log_line, string'("finished reading stimuli file")); writeline(output, v_log_line); in_file_data <= v_data; in_file_sync <= v_sync; in_file_val <= v_val; wait; end process; p_in_stimuli : process(clk, rst) begin if rst='1' then in_re <= (others=>'0'); in_im <= (others=>'0'); in_sync <= '0'; in_val <= '0'; in_index <= 0; in_repeat <= 0; elsif rising_edge(clk) then in_sync <= '0'; in_val <= '0'; -- start stimuli some arbitrary time after rst release to ensure that the proper behaviour of the DUT does not depend on that time if enable='1' then -- use always active input (the in_file contents may still contain blocks with in_val='0') or use random active input if in_en='1' then if in_index<c_file_len-1 then in_index <= in_index+1; else in_index <= 0; in_repeat <= in_repeat + 1; end if; if in_repeat < c_repeat then in_re <= std_logic_vector(to_signed(in_file_data(in_index, 1), g_in_dat_w)); in_im <= std_logic_vector(to_signed(in_file_data(in_index, 2), g_in_dat_w)); in_sync <= std_logic(in_file_sync(in_index)); in_val <= std_logic(in_file_val(in_index)); end if; if in_repeat > c_repeat then tb_end <= '1'; end if; end if; end if; end if; end process; -- DUT = Device Under Test u_rTwoSDF : entity work.rTwoSDF generic map( -- generics for the FFT g_use_reorder => g_use_reorder, g_in_dat_w => g_in_dat_w, g_out_dat_w => g_out_dat_w, g_stage_dat_w => c_stage_dat_w, g_guard_w => g_guard_w, g_nof_points => g_nof_points ) port map( clk => clk, rst => rst, in_re => in_re, in_im => in_im, in_val => in_val, out_re => out_re, out_im => out_im, out_val => out_val ); -- Read golden file with the expected DUT output p_read_golden_file : process 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 variable v_log_line : LINE; variable v_golden_line : LINE; variable v_index : integer :=0; variable v_comma : character; variable v_sync : std_logic_vector(0 to c_file_len-1):=(others=>'0'); variable v_val : std_logic_vector(0 to c_file_len-1):=(others=>'0'); variable v_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0)); begin -- wait 1 clock cycle to avoid that the output messages in the transcript window get lost in the 0 ps start up messages proc_common_wait_some_cycles(clk, 1); -- combinatorially read the file into the array write(v_log_line, string'("reading golden file : ")); write(v_log_line, c_goldenFile); writeline(output, v_log_line); loop exit when endfile(v_golden); readline(v_golden, v_golden_line); read(v_golden_line, v_sync(v_index)); -- sync read(v_golden_line, v_comma); read(v_golden_line, v_val(v_index)); -- valid read(v_golden_line, v_comma); read(v_golden_line, v_data(v_index,1)); -- real read(v_golden_line, v_comma); read(v_golden_line, v_data(v_index,2)); -- imag v_index := v_index + 1; end loop; write(v_log_line, string'("finished reading golden file")); writeline(output, v_log_line); gold_file_data <= v_data; gold_file_sync <= v_sync; gold_file_val <= v_val; wait; end process; -- Show read data in Wave Window for debug purposes gold_index <= gold_index + 1 when rising_edge(clk) and out_val='1'; flip_index <= (gold_index / g_nof_points) * g_nof_points + flip(gold_index mod g_nof_points, c_nof_points_w); gold_sync <= gold_file_sync(gold_index); gold_re <= gold_file_data(gold_index,1) when g_use_reorder=true else gold_file_data(flip_index,1); gold_im <= gold_file_data(gold_index,2) when g_use_reorder=true else gold_file_data(flip_index,2); -- Verify the output of the DUT with the expected output from the golden reference file p_verify_output : process(clk) begin -- Compare if rising_edge(clk) then if out_val='1' and gold_index <= gold_index_max then -- only write when out_val='1', because then the file is independent of cycles with invalid out_dat assert out_sync = gold_sync report "Output sync error" severity error; assert TO_SINT(out_re) = gold_re report "Output real data error" severity error; assert TO_SINT(out_im) = gold_im report "Output imag data error" severity error; end if; end if; end process; -- Write to default output file, this allows using command line diff or graphical diff viewer to compare it with the golden result file p_write_output_file : process(clk) 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 variable v_line : LINE; begin if rising_edge(clk) then if out_val='1' then -- only write when out_val='1', because then the file is independent of cycles with invalid out_dat write(v_line, out_sync); write(v_line, string'(",")); write(v_line, out_val); write(v_line, string'(",")); write(v_line, to_integer(signed(out_re))); write(v_line, string'(",")); write(v_line, to_integer(signed(out_im))); writeline(v_output, v_line); end if; end if; end process; end tb;
Go to most recent revision | Compare with Previous | Blame | View Log