Skip to content
Snippets Groups Projects
Commit 6bcf2897 authored by Pepping's avatar Pepping
Browse files

Copy

parent 00a95172
Branches
No related tags found
No related merge requests found
-- 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)
-- > do wave_rTwoSDF.do
-- > run -all
-- . it may be necessary to rescale the analogue formats in the Wave
-- window after running the simulation.
--
-- 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.
--
-- . The generic g_post_sim can be used to switch between functional simulation
-- and timing simulation. Note that the entity name of the timing model from
-- the .vho file must be changed to rTwoSDF_t.
library ieee, common_lib;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.std_logic_textio.all;
use STD.textio.all;
use common_lib.common_pkg.all;
use common_lib.common_lfsr_sequences_pkg.all;
use common_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
g_post_sim : boolean := false;
-- generics for rTwoSDF
g_use_reorder : boolean := true;
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.
-- Internal pipeline settings for rTwoSDF
g_pipeline : t_fft_pipeline := (1, 1, 3, 1, 1, 0, 0, 1) -- type t_rtwo_sdf_stage_pipeline is record
-- -- generics for rTwoSDFStage
-- stage_lat : natural; -- = 1
-- weight_lat : natural; -- = 1
-- mul_lat : natural; -- = 3
-- -- generics for rTwoBFStage
-- bf_lat : natural; -- = 1
-- -- generics for rTwoBF
-- bf_use_zdly : natural; -- = 1
-- bf_in_a_zdly : natural; -- = 0
-- bf_out_d_zdly : natural; -- = 0
-- sep_lat : natural; -- = 1
-- end record;
);
end entity tb_rTwoSDF;
architecture tb of tb_rTwoSDF is
constant c_clk_period : time := 20 ns;
-- 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 := "../../../tb/data/test/in/uniNoise_p" & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w) &"_in.txt";
constant c_noiseGoldenFile : string := "../../../tb/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 := "../../../tb/data/test/out/uniNoise_out.txt";
-- input from manually created file
constant c_impulseInputFile : string := "../../../tb/data/test/in/impulse_p" & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w)& "_in.txt";
constant c_impulseGoldenFile : string := "../../../tb/data/test/out/impulse_p" & natural'image(g_nof_points)& "_b"& natural'image(g_in_dat_w)& "_out.txt";
constant c_impulseOutputFile : string := "../../../tb/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 : 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;
gen_func_dut : if g_post_sim = FALSE generate
-- 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,
-- generics for rTwoSDFStage
g_pipeline => g_pipeline
)
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
);
end generate;
-- In case a timing simulation should be made the next code
-- should be un-commented. And the name of the timing varina entity
-- in the .vho file must be renamed to rTwoSDF_t.
-- gen_time_dut : if g_post_sim = TRUE generate
-- -- DUT = Device Under Test
-- u_rTwoSDF_t : entity work.rTwoSDF_t
-- 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
-- );
-- end generate;
-- 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';
gold_sync <= gold_file_sync(gold_index);
gold_re <= gold_file_data(gold_index,1);
gold_im <= gold_file_data(gold_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' 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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment