diff --git a/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_single.vhd b/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_single.vhd new file mode 100644 index 0000000000000000000000000000000000000000..c0304fe5fb76184b61119d3d6a68524683def62f --- /dev/null +++ b/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_single.vhd @@ -0,0 +1,207 @@ +-- Author: Harm Jan Pepping : HJP at astron.nl: April 2012 +-------------------------------------------------------------------------------- +-- +-- 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 single channel Poly Phase Filter unit +-- +-- The testbech inserts an impulse on every band. The output +-- is verified by checking if the output values equal the +-- filter coefficients: It verifies the impulse-response. +-- +-- Usage: +-- > run -all +-- > testbench is selftesting. The first four spectrums are verified. +-- + +library ieee, common_lib, dp_lib, diag_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_mem_pkg.ALL; +use common_lib.tb_common_pkg.all; +use common_lib.tb_common_mem_pkg.ALL; +use dp_lib.dp_stream_pkg.ALL; +use work.fil_pkg.all; + +entity tb_fil_ppf_single is + generic( + -- generics for tb + g_fil_ppf_pipeline : t_fil_ppf_pipeline := (1, 1, 1, 1, 1, 1, 0); + -- type t_fil_pipeline is record + -- -- generic for the taps and coefficients memory + -- mem_delay : natural; -- = 2 + -- -- generics for the multiplier in in the filter unit + -- mult_input : natural; -- = 1 + -- mult_product : natural; -- = 1 + -- mult_output : natural; -- = 1 + -- -- generics for the adder tree in in the filter unit + -- adder_stage : natural; -- = 1 + -- -- generics for the requantizer in the filter unit + -- requant_remove_lsb : natural; -- = 1 + -- requant_remove_msb : natural; -- = 0 + -- end record; + g_fil_ppf : t_fil_ppf := (1, 2, 512, 16, 4, 8, 23, 16); + -- type t_fil_ppf is record + -- wb_factor : natural; -- = 1, the wideband factor + -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan + -- nof_bands : natural; -- = 512, the number of subbands is N/2 (N=nof_points of the FFT) + -- nof_taps : natural; -- = 16, the number of FIR taps per subband + -- nof_streams : natural; -- = 1, the number of streams that are served by the same coefficients. + -- in_dat_w : natural; -- = 8, number of input bits per stream + -- out_dat_w : natural; -- = 23, number of output bits (per stream). It is set to 23 to be sure the requantizer does not remove + -- any of the data in order to be able to verify with the original coefficients values. + -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients + -- end record; + g_file_index_arr : t_nat_natural_arr := array_init(0, 128, 1); + g_coefs_file_prefix : string := "../../data/coef" + ); +end entity tb_fil_ppf_single; + +architecture tb of tb_fil_ppf_single is + + constant c_clk_period : time := 10 ns; + constant c_nof_coefs : natural := g_fil_ppf.nof_taps*g_fil_ppf.nof_bands*2**g_fil_ppf.nof_chan; + + -- input/output data width + + constant c_in_dat_w : natural := g_fil_ppf.in_dat_w; + constant c_out_dat_w : natural := g_fil_ppf.out_dat_w; + + -- signal definitions + signal tb_end : std_logic := '0'; + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + signal ram_coefs_mosi : t_mem_mosi; + signal ram_coefs_miso : t_mem_miso; + + signal in_dat : std_logic_vector(c_in_dat_w*g_fil_ppf.nof_streams-1 downto 0); + signal in_val : std_logic; + + signal out_dat : std_logic_vector(c_out_dat_w*g_fil_ppf.nof_streams-1 downto 0); + signal out_val : std_logic; + + signal ref_dat_arr : t_integer_arr(c_nof_coefs-1 downto 0); + signal ref_arr : t_integer_arr(g_fil_ppf.nof_bands-1 downto 0); + signal ref_dat : integer; + signal ref_index : natural; + +begin + + clk <= (not clk) or tb_end after c_clk_period/2; + rst <= '1', '0' after c_clk_period*7; + + + ram_coefs_mosi <= c_mem_mosi_rst; -- Reset the master out interface + --------------------------------------------------------------- + -- SEND IMPULSE TO THE DATA INPUT + --------------------------------------------------------------- + p_send_impulse : PROCESS + BEGIN + tb_end <= '0'; + in_dat <= (OTHERS => '0'); + in_val <= '0'; + proc_common_wait_until_low(clk, rst); -- Wait until reset has finished + proc_common_wait_some_cycles(clk, 10); -- Wait an additional amount of cycles + FOR I IN 0 TO g_fil_ppf.nof_bands*(2**g_fil_ppf.nof_chan)-1 LOOP + FOR J in 0 To g_fil_ppf.nof_streams-1 LOOP + in_dat((J+1)*c_in_dat_w-1 DOWNTO J*c_in_dat_w) <= TO_UVEC(1, c_in_dat_w); + END LOOP; + in_val <= '1'; + proc_common_wait_some_cycles(clk, 1); + END LOOP; + FOR J IN 0 TO g_fil_ppf.nof_taps-2 + 2 LOOP + FOR I IN 0 TO g_fil_ppf.nof_bands-1 LOOP + in_dat <= (OTHERS => '0'); + in_val <= '1'; + proc_common_wait_some_cycles(clk, 1); + END LOOP; + END LOOP; + in_dat <= (OTHERS => '0'); + in_val <= '0'; + proc_common_wait_some_cycles(clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + + --------------------------------------------------------------- + -- CREATE REFERENCE ARRAY + --------------------------------------------------------------- + p_create_ref : PROCESS + begin + for J in 0 to g_fil_ppf.nof_taps-1 loop + proc_common_read_mif_file(g_coefs_file_prefix & "_" & integer'image(J) & ".mif", ref_arr); + wait for 1 ns; + for I in 0 to g_fil_ppf.nof_bands-1 loop + for K in 0 to 2**g_fil_ppf.nof_chan-1 loop + ref_dat_arr(J*g_fil_ppf.nof_bands*2**g_fil_ppf.nof_chan + I*2**g_fil_ppf.nof_chan + K) <= TO_SINT(TO_UVEC(ref_arr(I), 16)); + end loop; + end loop; + end loop; + wait; + end process; + + --------------------------------------------------------------- + -- MAKE THE REFERENCE STREAM + --------------------------------------------------------------- + ref_index <= ref_index + 1 when rising_edge(clk) and out_val='1' and ref_index < c_nof_coefs-1; + ref_dat <= ref_dat_arr(ref_index); + + --------------------------------------------------------------- + -- DUT = Device Under Test + --------------------------------------------------------------- + u_dut : entity work.fil_ppf_single + generic map ( + g_fil_ppf => g_fil_ppf, + g_fil_ppf_pipeline => g_fil_ppf_pipeline, + g_file_index_arr => g_file_index_arr, + g_coefs_file_prefix => g_coefs_file_prefix + ) + port map ( + dp_clk => clk, + dp_rst => rst, + mm_clk => clk, + mm_rst => rst, + ram_coefs_mosi => ram_coefs_mosi, + ram_coefs_miso => ram_coefs_miso, + in_dat => in_dat, + in_val => in_val, + out_dat => out_dat, + out_val => out_val + ); + + -- Verify the output of the DUT with the expected output from the reference array + p_verify_output : process(clk) + begin + -- Compare + if rising_edge(clk) then + if out_val='1' and ref_index < c_nof_coefs-1 then + for I in 0 to g_fil_ppf.nof_streams-1 loop + assert TO_SINT(out_dat((I+1)*g_fil_ppf.out_dat_w-1 downto I*g_fil_ppf.out_dat_w)) = ref_dat report "Output data error" severity error; + end loop; + end if; + end if; + end process; + +end tb; \ No newline at end of file diff --git a/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide.vhd b/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f962f7fd5096c54256b9baa5f60d2f1031658f83 --- /dev/null +++ b/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide.vhd @@ -0,0 +1,270 @@ +-- Author: Harm Jan Pepping : HJP at astron.nl: April 2012 +-------------------------------------------------------------------------------- +-- +-- 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 multi channel Poly Phase PreFilter unit +-- +-- The testbech inserts an impulse on every band. The output +-- is verified by checking if the output values equal the +-- filter coefficients: It verifies the impulse-response. +-- +-- It is possible to vary wb_factor, nof_chan, nof_bands, nof_taps +-- and nof_streams. +-- Note that for each specific combination of wb_factor, nof_bands +-- and nof_taps a new set of mif-files must be created. The mif-files +-- are used to initially load the coefficients in the rams. +-- Use the script ../../src/python/create_mifs.py to create the required +-- mif files. +-- For wb_factor = 2, nof_bands = 1024, nof_taps = 8 the script +-- should be called like this: +-- +-- > create_mifs.py -t 8 -b 1024 -w 2 +-- +-- The generated mif files will be placed in ../../build/data/ +-- +-- +-- Usage: +-- > run -all +-- > testbench is selftesting. +-- + +library ieee, common_lib, dp_lib, diag_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_mem_pkg.ALL; +use common_lib.tb_common_pkg.all; +use common_lib.tb_common_mem_pkg.ALL; +use dp_lib.dp_stream_pkg.ALL; +use work.fil_pkg.all; + +entity tb_fil_ppf_wide is + generic( + -- generics for tb + g_fil_ppf_pipeline : t_fil_ppf_pipeline := (1, 1, 1, 1, 1, 1, 0); + -- type t_fil_pipeline is record + -- -- generic for the taps and coefficients memory + -- mem_delay : natural; -- = 1 + -- -- generics for the multiplier in in the filter unit + -- mult_input : natural; -- = 1 + -- mult_product : natural; -- = 1 + -- mult_output : natural; -- = 1 + -- -- generics for the adder tree in in the filter unit + -- adder_stage : natural; -- = 1 + -- end record; + -- type t_fil_pipeline is record + -- -- generic for the taps and coefficients memory + -- mem_delay : natural; -- = 2 + -- -- generics for the multiplier in in the filter unit + -- mult_input : natural; -- = 1 + -- mult_product : natural; -- = 1 + -- mult_output : natural; -- = 1 + -- -- generics for the adder tree in in the filter unit + -- adder_stage : natural; -- = 1 + -- -- generics for the requantizer in the filter unit + -- requant_remove_lsb : natural; -- = 1 + -- requant_remove_msb : natural; -- = 0 + -- end record; + g_fil_ppf : t_fil_ppf := (4, 2, 1024, 16, 2, 8, 23, 16); + -- type t_fil_ppf is record + -- wb_factor : natural; -- = 4, the wideband factor + -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan + -- nof_bands : natural; -- = 1024, the number of subbands is N/2 (N=nof_points of the FFT) + -- nof_taps : natural; -- = 16, the number of FIR taps per subband + -- nof_streams : natural; -- = 1, the number of streams that are served by the same coefficients. + -- in_dat_w : natural; -- = 8, number of input bits per stream + -- out_dat_w : natural; -- = 23, number of output bits. It is set to 23 to be sure the requantizer does not removes + -- any of the data in order to be able to verify with the original coefficients values. + -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients + -- end record; + g_file_index_arr : t_nat_natural_arr := array_init(0, 128, 1); + g_coefs_file_prefix : string := "../../data/coefs_wide" + ); +end entity tb_fil_ppf_wide; + +architecture tb of tb_fil_ppf_wide is + + constant c_clk_period : time := 10 ns; + constant c_nof_coefs : natural := g_fil_ppf.nof_taps*g_fil_ppf.nof_bands; + + constant c_coefs_file_prefix : string := g_coefs_file_prefix & natural'image(g_fil_ppf.wb_factor) & "_p"& natural'image(g_fil_ppf.nof_bands) & "_t"& natural'image(g_fil_ppf.nof_taps); + + -- input/output data width + constant c_in_dat_w : natural := g_fil_ppf.in_dat_w; + constant c_out_dat_w : natural := g_fil_ppf.in_dat_w + g_fil_ppf.coef_dat_w + ceil_log2(g_fil_ppf.nof_taps); + constant c_nof_bands_per_stream : natural := g_fil_ppf.nof_bands / g_fil_ppf.wb_factor; + constant c_nof_chan : natural := 2**g_fil_ppf.nof_chan; + + type t_integer_arr2 is array(integer range <> ) of t_integer_arr(c_nof_coefs/g_fil_ppf.wb_factor-1 downto 0); + + -- signal definitions + signal tb_end : std_logic := '0'; + signal clk : std_logic := '0'; + signal rst : std_logic := '0'; + + signal ram_coefs_mosi : t_mem_mosi; + signal ram_coefs_miso : t_mem_miso; + signal coefs_arr : t_integer_arr (c_nof_bands_per_stream-1 downto 0); + + signal in_dat_arr : t_fil_slv_arr(g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 downto 0); + signal in_val : std_logic; + + signal out_dat_arr : t_fil_slv_arr(g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 downto 0); + signal out_val : std_logic; + + signal ref_dat_arr : t_integer_arr (g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 downto 0); + signal ref_dat_arr2 : t_integer_arr2(g_fil_ppf.wb_factor-1 downto 0); + signal ref_arr : t_integer_arr (c_nof_bands_per_stream-1 downto 0); + signal ref_index : natural := 0; + signal chn_index : natural := 0; + signal coefs_mem_write : boolean := FALSE; + +begin + + clk <= (not clk) or tb_end after c_clk_period/2; + rst <= '1', '0' after c_clk_period*7; + + --------------------------------------------------------------- + -- WRITE THE COEFFICIENTS TO THE COEFS MEMORY + --------------------------------------------------------------- + p_coefs_memory_write : process + begin + coefs_mem_write <= FALSE; + ram_coefs_mosi <= c_mem_mosi_rst; -- Reset the master out interface + for K in 0 to g_fil_ppf.wb_factor-1 loop + for J in 0 to g_fil_ppf.nof_taps-1 loop + proc_common_read_mif_file(c_coefs_file_prefix & "_" & integer'image(k*g_fil_ppf.nof_taps+J) & ".mif", coefs_arr); + wait for 1 ns; + for I in 0 to c_nof_bands_per_stream-1 loop + proc_mem_mm_bus_wr(K*c_nof_bands_per_stream*g_fil_ppf.nof_taps + J*c_nof_bands_per_stream + I, coefs_arr(I), clk, ram_coefs_mosi); -- Write the coefficient to the memory + end loop; + end loop; + end loop; + coefs_mem_write <= TRUE; + wait; + end process; + + --------------------------------------------------------------- + -- SEND IMPULSE TO THE DATA INPUT + --------------------------------------------------------------- + p_send_impulse : process + begin + tb_end <= '0'; + for I in 0 to g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 loop + in_dat_arr(I) <= (others => '0'); + end loop; + in_val <= '0'; + proc_common_wait_until_low(clk, rst); -- Wait until reset has finished + proc_common_wait_some_cycles(clk, 10); -- Wait an additional amount of cycles + wait until coefs_mem_write = TRUE; + for J in 0 to c_nof_chan*c_nof_bands_per_stream-1 loop + for I in 0 to g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 loop + in_dat_arr(I) <= TO_UVEC(1, in_dat_arr(I)'LENGTH); + in_val <= '1'; + end loop; + proc_common_wait_some_cycles(clk, 1); + end loop; + for K in 0 to g_fil_ppf.nof_taps-2 + 2 loop + for J in 0 to c_nof_chan*c_nof_bands_per_stream-1 loop + for I in 0 to g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 loop + in_dat_arr(I) <= (others => '0'); + in_val <= '1'; + end loop; + proc_common_wait_some_cycles(clk, 1); + end loop; + end loop; + for I in 0 to g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 loop + in_dat_arr(I) <= (others => '0'); + in_val <= '0'; + end loop; + proc_common_wait_some_cycles(clk, 10); + tb_end <= '1'; + wait; + end process; + + --------------------------------------------------------------- + -- CREATE REFERENCE ARRAY + --------------------------------------------------------------- + p_create_ref : process + begin + for K in 0 to g_fil_ppf.wb_factor-1 loop + for J in 0 to g_fil_ppf.nof_taps-1 loop + proc_common_read_mif_file(c_coefs_file_prefix & "_" & integer'image(k*g_fil_ppf.nof_taps+J) & ".mif", ref_arr); + wait for 1 ns; + for I in 0 to c_nof_bands_per_stream-1 loop + ref_dat_arr2(K)(J*c_nof_bands_per_stream + I) <= TO_SINT(TO_UVEC(ref_arr(I), 16)); + end loop; + end loop; + end loop; + wait; + end process; + + --------------------------------------------------------------- + -- MAKE THE REFERENCE STREAM + --------------------------------------------------------------- + chn_index <= chn_index + 1 when (falling_edge(clk) and out_val='1') else 0 when (chn_index = c_nof_chan); + ref_index <= ref_index + 1 when rising_edge(clk) and out_val='1' and ref_index < c_nof_coefs/g_fil_ppf.wb_factor-1 and chn_index = 0; + assign_ref_dat_arr_wb : for I in 0 to g_fil_ppf.wb_factor-1 generate + assign_ref_dat_arr_streams : for J in 0 to g_fil_ppf.nof_streams-1 generate + ref_dat_arr(I*g_fil_ppf.nof_streams+J) <= ref_dat_arr2(I)(ref_index); + end generate; + end generate; + + --------------------------------------------------------------- + -- DUT = Device Under Test + --------------------------------------------------------------- + u_dut : entity work.fil_ppf_wide + generic map ( + g_fil_ppf => g_fil_ppf, + g_fil_ppf_pipeline => g_fil_ppf_pipeline, + g_file_index_arr => g_file_index_arr, + g_coefs_file_prefix => c_coefs_file_prefix + ) + port map ( + dp_clk => clk, + dp_rst => rst, + mm_clk => clk, + mm_rst => rst, + ram_coefs_mosi => ram_coefs_mosi, + ram_coefs_miso => ram_coefs_miso, + in_dat_arr => in_dat_arr, + in_val => in_val, + out_dat_arr => out_dat_arr, + out_val => out_val + ); + + -- Verify the output of the DUT with the expected output from the reference array + p_verify_output : process(clk) + begin + -- Compare + if rising_edge(clk) then + if out_val='1' and ref_index < c_nof_coefs/g_fil_ppf.wb_factor-1 then + for I in 0 to g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 loop + assert TO_SINT(out_dat_arr(I)(g_fil_ppf.out_dat_w-1 DOWNTO 0)) = ref_dat_arr(I) report "Output data error" severity error; + end loop; + end if; + end if; + end process; + +end tb; \ No newline at end of file