diff --git a/libraries/dsp/beamformer/hdllib.cfg b/libraries/dsp/beamformer/hdllib.cfg index 8bfd35cabbd50720afe8714a9c81bf54d9c4e7ad..af3f62e6dc84363fdf20e0dcc76883e93eff2e65 100644 --- a/libraries/dsp/beamformer/hdllib.cfg +++ b/libraries/dsp/beamformer/hdllib.cfg @@ -9,6 +9,7 @@ synth_files = test_bench_files = tb/vhdl/tb_beamformer.vhd + tb/vhdl/tb_tb_beamformer.vhd regression_test_vhdl = # no self checking tb available yet diff --git a/libraries/dsp/beamformer/tb/vhdl/tb_beamformer.vhd b/libraries/dsp/beamformer/tb/vhdl/tb_beamformer.vhd index eb057e72bf70593c963fcd2cc0b0b049864a82a9..08806444a1510df6b60fed379ccee4f24d9c0d0d 100644 --- a/libraries/dsp/beamformer/tb/vhdl/tb_beamformer.vhd +++ b/libraries/dsp/beamformer/tb/vhdl/tb_beamformer.vhd @@ -19,8 +19,9 @@ -- -------------------------------------------------------------------------------- --- Author: +-- Authors: -- . Daniel van der Schuur +-- . Pieter Donker -- Purpose: -- . -- Description: @@ -42,7 +43,7 @@ USE mm_lib.mm_file_pkg.ALL; ENTITY tb_beamformer IS GENERIC ( g_tb_index : NATURAL := 0; -- use different index to avoid MM file conflict in multi tb - g_technology : NATURAL := c_tech_select_default; + --g_technology : NATURAL := c_tech_select_default; g_nof_inputs : NATURAL := 2; g_nof_weights : NATURAL := 32; g_data_w : NATURAL := 8 --8b complex input data @@ -56,39 +57,33 @@ ARCHITECTURE tb OF tb_beamformer IS ----------------------------------------------------------------------------- CONSTANT c_dp_clk_period : TIME := 5 ns; CONSTANT c_mm_clk_period : TIME := 25 ns; - CONSTANT c_stimulus_period : TIME := 100 ns; - - SIGNAL tb_end : STD_LOGIC := '0'; - SIGNAL dp_clk : STD_LOGIC := '1'; - SIGNAL dp_rst : STD_LOGIC; - SIGNAL mm_clk : STD_LOGIC := '1'; - SIGNAL mm_rst : STD_LOGIC; - SIGNAL OK : STD_LOGIC := '1'; - SIGNAL verify_mm_en : STD_LOGIC := '1'; - SIGNAL verify_input_en : STD_LOGIC := '0'; - SIGNAL verify_sum_en : STD_LOGIC := '0'; - ----------------------------------------------------------------------------- - -- Block generator - ----------------------------------------------------------------------------- - CONSTANT c_bg_block_size : NATURAL := g_nof_weights; - CONSTANT c_bg_gapsize : NATURAL := c_bg_block_size; - CONSTANT c_bg_blocks_per_sync : NATURAL := 10; --not used - CONSTANT c_bg_ctrl : t_diag_block_gen := ('1', -- enable - '0', -- enable_sync - TO_UVEC( c_bg_block_size, c_diag_bg_samples_per_packet_w), - TO_UVEC(c_bg_blocks_per_sync, c_diag_bg_blocks_per_sync_w), - TO_UVEC( c_bg_gapsize, c_diag_bg_gapsize_w), - TO_UVEC( 0, c_diag_bg_mem_low_adrs_w), - TO_UVEC( c_bg_block_size-1, c_diag_bg_mem_high_adrs_w), - TO_UVEC( 0, c_diag_bg_bsn_init_w)); + -- Input data cont + CONSTANT c_in_block_size : NATURAL := g_nof_weights; + CONSTANT c_in_block_interval : NATURAL := c_in_block_size; + CONSTANT c_in_nof_blocks_per_sync : NATURAL := g_nof_weights; + CONSTANT c_in_sync_interval : NATURAL := c_in_block_interval*c_in_nof_blocks_per_sync; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL dp_clk : STD_LOGIC := '1'; + SIGNAL dp_rst : STD_LOGIC; + SIGNAL mm_clk : STD_LOGIC := '1'; + SIGNAL mm_rst : STD_LOGIC; + SIGNAL OK : STD_LOGIC := '1'; + SIGNAL mm_ok : STD_LOGIC := '1'; + SIGNAL addr_ok : STD_LOGIC := '1'; + SIGNAL data_ok : STD_LOGIC := '1'; + SIGNAL verify_mm_en : STD_LOGIC := '1'; + SIGNAL verify_addr_en : STD_LOGIC := '0'; + SIGNAL verify_data_en : STD_LOGIC := '0'; -- MM CONSTANT c_unb_nr : NATURAL := 0; CONSTANT c_node_nr : NATURAL := 0; -- choose node 0 is FN 0 CONSTANT c_mm_file_ram_beamformer : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_BEAMFORMER_" & int_to_str(g_tb_index); - SIGNAL block_gen_src_out_arr : t_dp_sosi_arr(1-1 DOWNTO 0); + SIGNAL src_in_enable : STD_LOGIC := '0'; + SIGNAL src_in : t_dp_sosi := c_dp_sosi_rst; ----------------------------------------------------------------------------- -- beamformer @@ -100,12 +95,18 @@ ARCHITECTURE tb OF tb_beamformer IS SIGNAL beamformer_snk_in_arr : t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0); SIGNAL beamformer_src_out : t_dp_sosi; - SIGNAL beamformer_weight_addr : STD_LOGIC_VECTOR(ceil_log2(g_nof_weights)-1 DOWNTO 0); + SIGNAL beamformer_weight_addr : STD_LOGIC_VECTOR(ceil_log2(g_nof_weights)-1 DOWNTO 0); + SIGNAL addr_stimulus_weight_addr : STD_LOGIC_VECTOR(ceil_log2(g_nof_weights)-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL data_stimulus_weight_addr : STD_LOGIC_VECTOR(ceil_log2(g_nof_weights)-1 DOWNTO 0) := (OTHERS=>'0'); SIGNAL rd_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -BEGIN + -- used to set src_in re data + SIGNAL src_re_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0) := "00000001"; + SIGNAL src_im_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0) := "00000001"; + + BEGIN ----------------------------------------------------------------------------- -- Clocks and reset ------------------------------------------------------------------------------- @@ -115,15 +116,50 @@ BEGIN mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2; mm_rst <= '1', '0' AFTER c_mm_clk_period*7; + ---------------------------------------------------------------------------- + -- Stimuli src_in + ---------------------------------------------------------------------------- + -- sync, valid, sop, eop + proc_common_gen_duty_pulse(0, 1, c_in_sync_interval, '1', dp_rst, dp_clk, src_in_enable, src_in.sync); + proc_common_gen_duty_pulse(0, c_in_block_size, c_in_block_interval, '1', dp_rst, dp_clk, src_in_enable, src_in.valid); + proc_common_gen_duty_pulse(0, 1, c_in_block_interval, '1', dp_rst, dp_clk, src_in_enable, src_in.sop); + proc_common_gen_duty_pulse(c_in_block_size-1, 1, c_in_block_interval, '1', dp_rst, dp_clk, src_in_enable, src_in.eop); -- DUT uses eop + -- bsn + src_in.bsn <= INCR_UVEC(src_in.bsn, 1) WHEN rising_edge(dp_clk) AND src_in.eop='1'; + -- re/im data + src_in.re <= TO_DP_DSP_DATA(TO_UINT(src_re_data)); + src_in.im <= TO_DP_DSP_DATA(TO_UINT(src_im_data)); + + -- set master OK + OK <= mm_ok and addr_ok and data_ok; + + -- change beamformer weights address from multiple processes + set_weights : PROCESS(verify_addr_en, addr_stimulus_weight_addr, verify_data_en, data_stimulus_weight_addr) + BEGIN + beamformer_weight_addr <= TO_UVEC(0, ceil_log2(g_nof_weights)); + + IF verify_addr_en = '1' THEN + beamformer_weight_addr <= addr_stimulus_weight_addr; + END IF; + + IF verify_data_en = '1' THEN + beamformer_weight_addr <= data_stimulus_weight_addr; + END IF; + END PROCESS; + -- first check, write/read weight to/from RAM mm_stimulus: PROCESS BEGIN IF verify_mm_en = '1' THEN - + -- wait for reset proc_common_wait_until_low(mm_clk, mm_rst); proc_common_wait_until_low(dp_clk, dp_rst); proc_common_wait_some_cycles(dp_clk, 10); + -- enable src_in generator + src_in_enable <= '1'; + proc_common_wait_until_hi_lo(dp_clk, src_in.sync); + REPORT "Start mm stumulus"; FOR I IN 0 TO g_nof_inputs-1 LOOP FOR J IN 0 TO g_nof_weights-1 LOOP @@ -136,82 +172,99 @@ BEGIN FOR J IN 0 TO g_nof_weights-1 LOOP -- read back MM page mmf_mm_bus_rd(c_mm_file_ram_beamformer, I*g_nof_weights+J, rd_data, mm_clk); - IF UNSIGNED(rd_data) /= J THEN - OK <= '0'; + IF TO_UINT(rd_data) /= J THEN + ASSERT FALSE + REPORT "MM Wrong weight" & + ", expected=" & int_to_str(J) & + ", readback=" & int_to_str(INTEGER(TO_UINT(rd_data))) + SEVERITY ERROR; + mm_ok <= '0'; END IF; - ASSERT TO_UINT(rd_data)=J - REPORT "MM Wrong weight, expected=" & int_to_str(J) & ", readback=" & int_to_str(INTEGER(TO_UINT(rd_data))) - SEVERITY ERROR; + END LOOP; END LOOP; - verify_sum_en <= '1'; + verify_addr_en <= '1'; -- enable second check END IF; WAIT; END PROCESS; - - weights_addr_stimulus: PROCESS + -- second check, activate weights and check effect on output + addr_stimulus: PROCESS BEGIN - proc_common_wait_until_high(dp_clk, verify_sum_en); + proc_common_wait_until_high(dp_clk, verify_addr_en); REPORT "Start weights addr stimulus"; -- loop over all weights adresses FOR i IN 0 TO g_nof_weights-1 LOOP - REPORT "Start weights addr stimulus for weight " & int_to_str(i); - beamformer_weight_addr <= STD_LOGIC_VECTOR(TO_UNSIGNED(i, ceil_log2(g_nof_weights))); - WAIT FOR c_stimulus_period; - proc_common_wait_until_high(dp_clk, beamformer_src_out.valid); - IF UNSIGNED(beamformer_weight_addr)*g_nof_inputs /= UNSIGNED(beamformer_src_out.re) THEN - OK <= '0'; + --REPORT "Start weights addr stimulus for weight " & int_to_str(i); + addr_stimulus_weight_addr <= TO_UVEC(i, ceil_log2(g_nof_weights)); + proc_common_wait_some_cycles(dp_clk, 5+ceil_log2(g_nof_inputs)); + IF TO_UINT(beamformer_weight_addr)*g_nof_inputs /= TO_UINT(beamformer_src_out.re) THEN + ASSERT FALSE + REPORT "Beamformer wrong weights" & + ", expected=" & int_to_str(TO_UINT(beamformer_weight_addr)*g_nof_inputs) & + ", readback=" & int_to_str(TO_UINT(beamformer_src_out.re)) + SEVERITY ERROR; + addr_ok <= '0'; END IF; - ASSERT UNSIGNED(beamformer_weight_addr)*g_nof_inputs = UNSIGNED(beamformer_src_out.re) - REPORT "Beamformer wrong weights" & - ", expected=" & int_to_str(TO_SINT(beamformer_weight_addr)*g_nof_inputs) & - ", readback=" & int_to_str(TO_SINT(beamformer_src_out.re)) - SEVERITY ERROR; + + END LOOP; - tb_end <= '1'; -- end test + verify_data_en <= '1'; -- enable third check WAIT; END PROCESS; + -- third check, change input data and check effect on output + data_stimulus: PROCESS + BEGIN + proc_common_wait_until_high(dp_clk, verify_data_en); + + REPORT "Start data stimulus"; + -- loop over weight address 1..2 + FOR I IN 1 TO 2 LOOP + data_stimulus_weight_addr <= TO_UVEC(I, ceil_log2(g_nof_weights)); + proc_common_wait_some_cycles(dp_clk, 2); + -- loop over input data.re 1..127 + FOR J IN 1 TO 127 LOOP + --REPORT "Start data stimulus with input " & int_to_str(i); + src_re_data <= TO_UVEC(J, g_data_w); + proc_common_wait_some_cycles(dp_clk, 4+ceil_log2(g_nof_inputs)+1); + IF TO_UINT(beamformer_weight_addr)*g_nof_inputs*J /= TO_UINT(beamformer_src_out.re) THEN + ASSERT FALSE + REPORT "Beamformer wrong data" & + ", expected=" & int_to_str(TO_UINT(beamformer_weight_addr)*g_nof_inputs*J) & + ", readback=" & int_to_str(TO_UINT(beamformer_src_out.re)) + SEVERITY ERROR; + data_ok <= '0'; + END IF; + END LOOP; -- input data + END LOOP; -- weigth address + IF OK = '0' THEN + REPORT "TEST WENT WRONG."; + ELSE + REPORT "Test succesfull ended."; + END IF; - ----------------------------------------------------------------------------- - -- Block generator: - -- . X pol = complex( 1, 1) - -- . Y pol = complex(-1,-1) - ----------------------------------------------------------------------------- - u_mms_diag_block_gen : ENTITY diag_lib.mms_diag_block_gen - GENERIC MAP ( - g_nof_streams => 1, - g_buf_dat_w => g_data_w, - g_buf_addr_w => ceil_log2(TO_UINT(c_bg_ctrl.samples_per_packet)), - g_file_name_prefix => "hex/mms_diag_block_gen", - g_diag_block_gen_rst => c_bg_ctrl - ) - PORT MAP ( - mm_clk => mm_clk, - mm_rst => mm_rst, - - dp_clk => dp_clk, - dp_rst => dp_rst, + tb_end <= '1'; -- end test + WAIT; + END PROCESS; - out_sosi_arr => block_gen_src_out_arr - ); ----------------------------------------------------------------------------- -- beamformer for each TAB ----------------------------------------------------------------------------- u_mm_file_ram_beamformer : ENTITY mm_lib.mm_file GENERIC MAP(c_mm_file_ram_beamformer) PORT MAP(mm_rst, mm_clk, ram_beamformer_mosi, ram_beamformer_miso); + -- assign input_source to snk_in_arr gen_beamformer_snk_in_arr : FOR i IN 0 TO g_nof_inputs-1 GENERATE - beamformer_snk_in_arr(i) <= block_gen_src_out_arr(0); -- Copy the block gen stream 'g_nof_inputs' times + beamformer_snk_in_arr(i) <= src_in; -- Copy the block gen stream 'g_nof_inputs' times END GENERATE; u_beamformer : ENTITY work.beamformer GENERIC MAP ( - g_technology => g_technology, + g_technology => c_tech_select_default, g_nof_inputs => g_nof_inputs, g_nof_weights => g_nof_weights, g_data_w => g_data_w, @@ -232,5 +285,6 @@ BEGIN src_out => beamformer_src_out ); - END tb; + + diff --git a/libraries/dsp/beamformer/tb/vhdl/tb_tb_beamformer.vhd b/libraries/dsp/beamformer/tb/vhdl/tb_tb_beamformer.vhd new file mode 100644 index 0000000000000000000000000000000000000000..bde92449e7aa9357957a8a2bdcd4b8caf999e224 --- /dev/null +++ b/libraries/dsp/beamformer/tb/vhdl/tb_tb_beamformer.vhd @@ -0,0 +1,59 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2017 +-- 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/>. +-- +-------------------------------------------------------------------------------- + +-- Author: +-- . Pieter Donker +-- Purpose: +-- . +-- Description: +-- . + +LIBRARY IEEE, common_lib, dp_lib, technology_lib, diag_lib, mm_lib; +USE IEEE.std_logic_1164.ALL; + +ENTITY tb_tb_beamformer IS +END tb_tb_beamformer; + +ARCHITECTURE tb OF tb_tb_beamformer IS + SIGNAL tb_end : STD_LOGIC := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' +BEGIN + +-- Usage +-- > as 8 +-- > run -all +-- > Testbenches are self-checking + +-- +-- g_tb_index : NATURAL := 0; -- use different index to avoid MM file conflict in multi tb +-- --g_technology : NATURAL := c_tech_select_default; +-- g_nof_inputs : NATURAL := 2; +-- g_nof_weights : NATURAL := 32; +-- g_data_w : NATURAL := 8 --8b complex input data +-- + +-- do test for different number of inputs +sim_i1_beamformer : ENTITY work.tb_beamformer GENERIC MAP (1, 1, 32, 8); +sim_i2_beamformer : ENTITY work.tb_beamformer GENERIC MAP (2, 2, 32, 8); +sim_i3_beamformer : ENTITY work.tb_beamformer GENERIC MAP (3, 3, 32, 8); +sim_i8_beamformer : ENTITY work.tb_beamformer GENERIC MAP (4, 8, 32, 8); +sim_i32_beamformer : ENTITY work.tb_beamformer GENERIC MAP (5, 32, 32, 8); + +END tb; \ No newline at end of file