diff --git a/libraries/dsp/wpfb/hdllib.cfg b/libraries/dsp/wpfb/hdllib.cfg index 4aa236148846cd23847f3b3a7ae3e295fbd308ca..e657495e72ed8a3f6efbeeae88c712364517cd6f 100644 --- a/libraries/dsp/wpfb/hdllib.cfg +++ b/libraries/dsp/wpfb/hdllib.cfg @@ -14,5 +14,7 @@ synth_files = test_bench_files = $UNB/Firmware/dsp/wpfb/tb/vhdl/tb_wpfb_unit.vhd - $UNB/Firmware/dsp/wpfb/tb/vhdl/tb_mmf_wpfb_unit.vhd + tb/vhdl/tb_mmf_wpfb_unit.vhd +modelsim_copy_files = + $UNB/Firmware/dsp/filter/build/data data diff --git a/libraries/dsp/wpfb/tb/vhdl/tb_mmf_wpfb_unit.vhd b/libraries/dsp/wpfb/tb/vhdl/tb_mmf_wpfb_unit.vhd new file mode 100644 index 0000000000000000000000000000000000000000..b5d05f95fb8a528d6d81bb027ff8caca3999319a --- /dev/null +++ b/libraries/dsp/wpfb/tb/vhdl/tb_mmf_wpfb_unit.vhd @@ -0,0 +1,457 @@ + +------------------------------------------------------------------------------- +-- +-- 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 wideband poly phase filterbank. +-- +-- The testbech uses blockgenerators to generate data for +-- every input of the wideband poly phase filterbank. +-- The output of the WPFB is stored in databuffers. +-- Both the block generators and databuffers are controlled +-- via a mm interface. +-- Use this testbench in conjunction with: +-- +-- ../python/tc_mmf_wpfb_unit.py +-- For verifying the complete wideband polyphase filter bank: g_use_bg = FALSE +-- +-- ../python/tc_mmf_wpfb_unit_functional.py +-- For verifying the different wide- and narrowband configurationss +-- of the wpfb_unit. +-- +-- (Automated) Usage: +-- > Be sure that the c_start_modelsim variable is set to 1 in the script. +-- > Run python script in separate terminal: "python tc_mmf_wpfb_unit.py --unb 0 --bn 0 --sim" +-- +-- (Manual) Usage: +-- > run -all +-- > Be sure that the c_start_modelsim variable is set to 0 in the script. +-- > Run python script in separate terminal: "python tc_mmf_wpfb_unit.py --unb 0 --bn 0 --sim" +-- > Check the results of the python script. +-- > Stop the simulation manually in Modelsim by pressing the stop-button. +-- > For fractional frequencies set g_nof_blocks=32 to be able to simulate a sufficent number of periods without transition. + + +LIBRARY IEEE, common_lib, mm_lib, diag_lib, dp_lib, rTwoSDF_lib, fft_lib, filter_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE IEEE.math_real.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_str_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE mm_lib.mm_file_unb_pkg.ALL; +USE mm_lib.mm_file_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE rTwoSDF_lib.twiddlesPkg.all; +USE rTwoSDF_lib.rTwoSDFPkg.all; +USE fft_lib.tb_fft_pkg.all; +USE fft_lib.fft_pkg.all; +USE filter_lib.fil_pkg.all; +USE work.wpfb_pkg.all; + + +ENTITY tb_mmf_wpfb_unit IS + GENERIC( + g_wb_factor : natural := 1; -- = default 1, wideband factor + g_nof_wb_streams : natural := 1; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every wb-stream. + g_nof_chan : natural := 0; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan + g_nof_points : natural := 64; -- = 1024, N point FFT + g_nof_taps : natural := 16; -- = 8 nof taps n the filter + g_nof_blocks : natural := 4; -- = 4, the number of blocks of g_nof_points each in the BG waveform (must be power of 2 due to that BG c_bg_block_len must be power of 2) + g_in_dat_w : natural := 8; -- = 8, number of input bits + g_out_dat_w : natural := 16; -- = 14, number of output bits: in_dat_w + natural((ceil_log2(nof_points))/2) + g_use_separate : boolean := FALSE; -- = false for complex input, true for two real inputs + g_use_bg : boolean := FALSE; + g_file_index_arr : t_nat_natural_arr := array_init(0, 128, 1); + g_coefs_file_prefix : string := "data/coefs_wide" + ); +END tb_mmf_wpfb_unit; + +ARCHITECTURE tb OF tb_mmf_wpfb_unit IS + + CONSTANT c_wpfb : t_wpfb := (g_wb_factor, g_nof_points, g_nof_chan, g_nof_wb_streams, + g_nof_taps, g_in_dat_w, 16, 16, + true, g_use_separate, 16, g_out_dat_w, 18, 2, true, 56, 2, + c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline); + + -- type t_wpfb is record + -- -- General parameters for the wideband poly phase filter + -- wb_factor : natural; -- = default 4, wideband factor + -- nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filetr part) + -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan + -- nof_wb_streams : natural; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every stream. + -- + -- -- Parameters for the poly phase filter + -- nof_taps : natural; -- = 16, the number of FIR taps per subband + -- fil_in_dat_w : natural; -- = 8, number of input bits + -- fil_out_dat_w : natural; -- = 16, number of output bits + -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients + -- + -- -- Parameters for the FFT + -- use_reorder : boolean; -- = false for bit-reversed output, true for normal output + -- use_separate : boolean; -- = false for complex input, true for two real inputs + -- fft_in_dat_w : natural; -- = 16, number of input bits + -- fft_out_dat_w : natural; -- = 13, number of output bits + -- stage_dat_w : natural; -- = 18, number of bits that are used inter-stage + -- guard_w : natural; -- = 2 + -- guard_enable : boolean; -- = true + -- stat_data_w : positive; -- = 56 + -- stat_data_sz : positive; -- = 2 + -- + -- -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries. + -- pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT + -- fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT + -- fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units + -- + -- end record; + + ---------------------------------------------------------------------------- + -- Clocks and resets + ---------------------------------------------------------------------------- + CONSTANT c_mm_clk_period : TIME := 100 ps; + CONSTANT c_dp_clk_period : TIME := 5 ns; + CONSTANT c_sclk_period : TIME := c_dp_clk_period / c_wpfb.wb_factor; + CONSTANT c_dp_pps_period : NATURAL := 64; + + SIGNAL dp_pps : STD_LOGIC; + + SIGNAL mm_rst : STD_LOGIC; + SIGNAL mm_clk : STD_LOGIC := '0'; + + SIGNAL dp_rst : STD_LOGIC; + SIGNAL dp_clk : STD_LOGIC := '0'; + + SIGNAL SCLK : STD_LOGIC := '0'; + + ---------------------------------------------------------------------------- + -- MM buses + ---------------------------------------------------------------------------- + SIGNAL reg_diag_bg_mosi : t_mem_mosi; + SIGNAL reg_diag_bg_miso : t_mem_miso; + + SIGNAL ram_diag_bg_mosi : t_mem_mosi; + SIGNAL ram_diag_bg_miso : t_mem_miso; + + SIGNAL ram_diag_data_buf_re_mosi : t_mem_mosi; + SIGNAL ram_diag_data_buf_re_miso : t_mem_miso; + + SIGNAL reg_diag_data_buf_re_mosi : t_mem_mosi; + SIGNAL reg_diag_data_buf_re_miso : t_mem_miso; + + SIGNAL ram_diag_data_buf_im_mosi : t_mem_mosi; + SIGNAL ram_diag_data_buf_im_miso : t_mem_miso; + + SIGNAL reg_diag_data_buf_im_mosi : t_mem_mosi; + SIGNAL reg_diag_data_buf_im_miso : t_mem_miso; + + SIGNAL ram_st_sst_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL ram_st_sst_miso : t_mem_miso := c_mem_miso_rst; + + SIGNAL ram_fil_coefs_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL ram_fil_coefs_miso : t_mem_miso := c_mem_miso_rst; + + SIGNAL reg_diag_bg_pfb_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL reg_diag_bg_pfb_miso : t_mem_miso := c_mem_miso_rst; + + SIGNAL ram_diag_bg_pfb_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL ram_diag_bg_pfb_miso : t_mem_miso := c_mem_miso_rst; + + ---------------------------------------------------------------------------- + -- Component declaration of mm_file + ---------------------------------------------------------------------------- + COMPONENT mm_file + GENERIC( + g_file_prefix : STRING; + g_update_on_change : BOOLEAN := FALSE + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + mm_master_out : OUT t_mem_mosi; + mm_master_in : IN t_mem_miso + ); + END COMPONENT; + + CONSTANT c_coefs_file_prefix : STRING := g_coefs_file_prefix & NATURAL'IMAGE(c_wpfb.wb_factor) & "_p"& NATURAL'IMAGE(c_wpfb.nof_points) & "_t"& NATURAL'IMAGE(c_wpfb.nof_taps); + + CONSTANT c_nof_streams : POSITIVE := c_wpfb.nof_wb_streams*c_wpfb.wb_factor; + CONSTANT c_nof_channels : NATURAL := 2**c_wpfb.nof_chan; + CONSTANT c_bg_block_len : NATURAL := c_wpfb.nof_points*g_nof_blocks*c_nof_channels/c_wpfb.wb_factor; + + CONSTANT c_bg_buf_adr_w : NATURAL := ceil_log2(c_bg_block_len); + CONSTANT c_bg_data_file_index_arr : t_nat_natural_arr := array_init(0, c_nof_streams, 1); + CONSTANT c_bg_data_file_prefix : STRING := "UNUSED"; + + SIGNAL bg_siso_arr : t_dp_siso_arr(c_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + SIGNAL bg_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0); + SIGNAL out_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0); + + SIGNAL scope_in_sosi : t_dp_sosi_integer_arr(c_wpfb.nof_wb_streams-1 DOWNTO 0); + SIGNAL scope_out_sosi : t_dp_sosi_integer_arr(c_wpfb.nof_wb_streams-1 DOWNTO 0); + SIGNAL scope_out_power : REAL := 0.0; + SIGNAL scope_out_ampl : REAL := 0.0; + SIGNAL scope_out_index : NATURAL; + SIGNAL scope_out_bin : NATURAL; + SIGNAL scope_out_band : NATURAL; + SIGNAL scope_out_ampl_x : REAL := 0.0; + SIGNAL scope_out_ampl_y : REAL := 0.0; + +BEGIN + + ---------------------------------------------------------------------------- + -- Clock and reset generation + ---------------------------------------------------------------------------- + mm_clk <= NOT mm_clk AFTER c_mm_clk_period/2; + mm_rst <= '1', '0' AFTER c_mm_clk_period*5; + + dp_clk <= NOT dp_clk AFTER c_dp_clk_period/2; + dp_rst <= '1', '0' AFTER c_dp_clk_period*5; + + SCLK <= NOT SCLK AFTER c_sclk_period/2; + + ------------------------------------------------------------------------------ + -- External PPS + ------------------------------------------------------------------------------ + proc_common_gen_pulse(1, c_dp_pps_period, '1', dp_clk, dp_pps); + + ---------------------------------------------------------------------------- + -- Procedure that polls a sim control file that can be used to e.g. get + -- the simulation time in ns + ---------------------------------------------------------------------------- + mmf_poll_sim_ctrl_file(c_mmf_unb_file_path & "sim.ctrl", c_mmf_unb_file_path & "sim.stat"); + + ---------------------------------------------------------------------------- + -- MM buses + ---------------------------------------------------------------------------- + u_mm_file_reg_diag_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_BG") + PORT MAP(mm_rst, mm_clk, reg_diag_bg_mosi, reg_diag_bg_miso); + + u_mm_file_ram_diag_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_BG") + PORT MAP(mm_rst, mm_clk, ram_diag_bg_mosi, ram_diag_bg_miso); + + u_mm_file_ram_diag_data_buf_re : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_DATA_BUFFER_REAL") + PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_re_mosi, ram_diag_data_buf_re_miso); + + u_mm_file_reg_diag_data_buf_re : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_DATA_BUFFER_REAL") + PORT MAP(mm_rst, mm_clk, reg_diag_data_buf_re_mosi, reg_diag_data_buf_re_miso); + + u_mm_file_ram_diag_data_buf_im : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_DATA_BUFFER_IMAG") + PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_im_mosi, ram_diag_data_buf_im_miso); + + u_mm_file_reg_diag_data_buf_im : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_DATA_BUFFER_IMAG") + PORT MAP(mm_rst, mm_clk, reg_diag_data_buf_im_mosi, reg_diag_data_buf_im_miso); + + u_mm_file_ram_fil_coefs : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_FIL_COEFS") + PORT MAP(mm_rst, mm_clk, ram_fil_coefs_mosi, ram_fil_coefs_miso); + + u_mm_file_ram_st_sst : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_ST_SST") + PORT MAP(mm_rst, mm_clk, ram_st_sst_mosi, ram_st_sst_miso); + + u_mm_file_reg_diag_pfb_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_BG_PFB") + PORT MAP(mm_rst, mm_clk, reg_diag_bg_pfb_mosi, reg_diag_bg_pfb_miso); + + u_mm_file_ram_diag_pfb_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_BG_PFB") + PORT MAP(mm_rst, mm_clk, ram_diag_bg_pfb_mosi, ram_diag_bg_pfb_miso); + + ---------------------------------------------------------------------------- + -- Source: block generator + ---------------------------------------------------------------------------- + u_bg : ENTITY diag_lib.mms_diag_block_gen + GENERIC MAP( + g_nof_streams => c_nof_streams, + g_buf_dat_w => c_nof_complex*c_wpfb.fil_in_dat_w, + g_buf_addr_w => c_bg_buf_adr_w, -- Waveform buffer size 2**g_buf_addr_w nof samples + g_file_index_arr => c_bg_data_file_index_arr, + g_file_name_prefix => c_bg_data_file_prefix + ) + PORT MAP( + -- System + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + en_sync => dp_pps, + -- MM interface + reg_bg_ctrl_mosi => reg_diag_bg_mosi, + reg_bg_ctrl_miso => reg_diag_bg_miso, + ram_bg_data_mosi => ram_diag_bg_mosi, + ram_bg_data_miso => ram_diag_bg_miso, + -- ST interface + out_siso_arr => bg_siso_arr, + out_sosi_arr => bg_sosi_arr + ); + + ---------------------------------------------------------------------------- + -- Source: DUT input scope + ---------------------------------------------------------------------------- + gen_input_scopes : FOR I IN 0 TO c_wpfb.nof_wb_streams-1 GENERATE + u_in_scope : ENTITY dp_lib.dp_wideband_wb_arr_scope + GENERIC MAP ( + g_sim => TRUE, + g_wideband_factor => c_wpfb.wb_factor, + g_wideband_big_endian => FALSE, + g_dat_w => c_wpfb.fil_in_dat_w + ) + PORT MAP ( + SCLK => SCLK, + wb_sosi_arr => bg_sosi_arr((I+1)*c_wpfb.wb_factor-1 DOWNTO I*c_wpfb.wb_factor), + scope_sosi => scope_in_sosi(I) + ); + END GENERATE; + ---------------------------------------------------------------------------- + -- DUT = Device Under Test + ---------------------------------------------------------------------------- + u_dut : ENTITY work.wpfb_unit + GENERIC MAP( + g_wpfb => c_wpfb, + g_use_bg => g_use_bg, + g_file_index_arr => g_file_index_arr, + g_coefs_file_prefix => c_coefs_file_prefix + ) + PORT MAP( + dp_rst => dp_rst, + dp_clk => dp_clk, + mm_rst => mm_rst, + mm_clk => mm_clk, + ram_fil_coefs_mosi => ram_fil_coefs_mosi, + ram_fil_coefs_miso => ram_fil_coefs_miso, + ram_st_sst_mosi => ram_st_sst_mosi, + ram_st_sst_miso => ram_st_sst_miso, + reg_bg_ctrl_mosi => reg_diag_bg_pfb_mosi, + reg_bg_ctrl_miso => reg_diag_bg_pfb_miso, + ram_bg_data_mosi => ram_diag_bg_pfb_mosi, + ram_bg_data_miso => ram_diag_bg_pfb_miso, + in_sosi_arr => bg_sosi_arr, + out_sosi_arr => out_sosi_arr + ); + + time_map : process is + variable sim_time_str_v : string(1 to 30); -- 30 chars should be enough + variable sim_time_len_v : natural; + begin + wait for 1000 ns; + sim_time_len_v := time'image(now)'length; + sim_time_str_v := (others => ' '); + sim_time_str_v(1 to sim_time_len_v) := time'image(now); + report "Sim time string length: " & integer'image(sim_time_len_v); + report "Sim time string.......:'" & sim_time_str_v & "'"; + end process; + + ---------------------------------------------------------------------------- + -- Sink: DUT output scope + ---------------------------------------------------------------------------- + gen_output_scopes : FOR I IN 0 TO c_wpfb.nof_wb_streams-1 GENERATE + u_out_scope : ENTITY dp_lib.dp_wideband_wb_arr_scope + GENERIC MAP ( + g_sim => TRUE, + g_wideband_factor => c_wpfb.wb_factor, + g_wideband_big_endian => FALSE, + g_dat_w => c_wpfb.fft_out_dat_w + ) + PORT MAP ( + SCLK => SCLK, + wb_sosi_arr => out_sosi_arr((I+1)*c_wpfb.wb_factor-1 DOWNTO I*c_wpfb.wb_factor), + scope_sosi => scope_out_sosi(I) + ); + END GENERATE; + + p_scope_out_index : PROCESS(SCLK) + BEGIN + IF rising_edge(SCLK) THEN + IF scope_out_sosi(0).valid='1' THEN + scope_out_index <= scope_out_index+1; + IF scope_out_index>=g_nof_points-1 THEN + scope_out_index <= 0; + END IF; + END IF; + END IF; + END PROCESS; + scope_out_bin <= fft_index_to_bin_frequency(c_wpfb.wb_factor, c_wpfb.nof_points, scope_out_index, TRUE, FALSE, TRUE); -- complex bin + scope_out_band <= fft_index_to_bin_frequency(c_wpfb.wb_factor, c_wpfb.nof_points, scope_out_index, TRUE, TRUE, TRUE); -- two real bin + + scope_out_power <= REAL(scope_out_sosi(0).re)**2 + REAL(scope_out_sosi(0).im)**2; + scope_out_ampl <= SQRT(scope_out_power); + scope_out_ampl_x <= scope_out_ampl WHEN (scope_out_bin MOD 2)=0 ELSE 0.0; + scope_out_ampl_y <= scope_out_ampl WHEN (scope_out_bin MOD 2)=1 ELSE 0.0; + + ---------------------------------------------------------------------------- + -- Sink: data buffer real + ---------------------------------------------------------------------------- + u_data_buf_re : ENTITY diag_lib.mms_diag_data_buffer + GENERIC MAP ( + g_nof_streams => c_nof_streams, + g_data_type => e_real, + g_data_w => c_wpfb.fft_out_dat_w, + g_buf_nof_data => c_bg_block_len, + g_buf_use_sync => TRUE + ) + PORT MAP ( + -- System + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- MM interface + ram_data_buf_mosi => ram_diag_data_buf_re_mosi, + ram_data_buf_miso => ram_diag_data_buf_re_miso, + + reg_data_buf_mosi => reg_diag_data_buf_re_mosi, + reg_data_buf_miso => reg_diag_data_buf_re_miso, + + -- ST interface + in_sync => out_sosi_arr(0).sync, + in_sosi_arr => out_sosi_arr + ); + + ---------------------------------------------------------------------------- + -- Sink: data buffer imag + ---------------------------------------------------------------------------- + u_data_buf_im : ENTITY diag_lib.mms_diag_data_buffer + GENERIC MAP ( + g_nof_streams => c_nof_streams, + g_data_type => e_imag, + g_data_w => c_wpfb.fft_out_dat_w, + g_buf_nof_data => c_bg_block_len, + g_buf_use_sync => TRUE + ) + PORT MAP ( + -- System + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- MM interface + ram_data_buf_mosi => ram_diag_data_buf_im_mosi, + ram_data_buf_miso => ram_diag_data_buf_im_miso, + + reg_data_buf_mosi => reg_diag_data_buf_im_mosi, + reg_data_buf_miso => reg_diag_data_buf_im_miso, + + -- ST interface + in_sync => out_sosi_arr(0).sync, + in_sosi_arr => out_sosi_arr + ); + +END tb;