diff --git a/libraries/dsp/st/hdllib.cfg b/libraries/dsp/st/hdllib.cfg index faba09d3db7d4382948bb971bffd4a62e111bcd4..8b4e7ddfb49e185f428e9f73085d935dfbda8f80 100644 --- a/libraries/dsp/st/hdllib.cfg +++ b/libraries/dsp/st/hdllib.cfg @@ -10,7 +10,9 @@ synth_files = src/vhdl/st_calc.vhd src/vhdl/st_sst.vhd src/vhdl/st_xsq.vhd - src/vhdl/st_xsq_arr.vhd + src/vhdl/st_xsq_arr.vhd + src/vhdl/st_xsq_mm_to_dp.vhd + src/vhdl/st_xst.vhd # src/vhdl/st_top.vhd src/vhdl/st_histogram.vhd src/vhdl/st_histogram_reg.vhd @@ -25,6 +27,8 @@ test_bench_files = tb/vhdl/tb_mmf_st_sst.vhd tb/vhdl/tb_st_xsq.vhd tb/vhdl/tb_tb_st_xsq.vhd + tb/vhdl/tb_st_xst.vhd + tb/vhdl/tb_tb_st_xst.vhd tb/vhdl/tb_st_histogram.vhd tb/vhdl/tb_mms_st_histogram.vhd tb/vhdl/tb_tb_st_histogram.vhd @@ -32,6 +36,7 @@ test_bench_files = regression_test_vhdl = tb/vhdl/tb_st_acc.vhd tb/vhdl/tb_tb_st_xsq.vhd + tb/vhdl/tb_tb_st_xst.vhd #tb/vhdl/tb_st_calc.vhd -- tb is not self checking yet diff --git a/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd b/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd index 9db9e0d826cb5252aeb0f04fd5942ce043b078fd..81d0d66f60f3ee20b31d7f0b9cb604e0893f15e9 100644 --- a/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd +++ b/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd @@ -19,14 +19,16 @@ ------------------------------------------------------------------------------- -- Author : R. vd Walle -- Purpose: --- . Read a block of data from memory mapped (MM) location and stream it as a block of data. +-- . Read a block of xsq data with size (g_nof_crosslets * g_nof_signal_inputs) +-- from memory mapped (MM) location and stream it as a block of data of +-- size g_nof_crosslets * g_nof_signal_inputs **2. -- Description: --- After every in_sosi.sop the st_xsq_mm_to_dp.vhd reads g_nof_streams blocks of data --- via mm and outputs it as g_nof_streams parallel streams via out_sosi_arr. in_sosi.sync is --- passed on to out_sosi. +-- After every in_sosi.sop the st_xsq_mm_to_dp.vhd reads blocks of data +-- via g_nof_streams mm and outputs it as g_nof_streams parallel streams via +-- out_sosi_arr. In_sosi.sync is passed on to out_sosi. -- -------------------------------------------------------------------------- -LIBRARY IEEE,common_lib; +LIBRARY IEEE,common_lib, dp_lib; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; USE common_lib.common_pkg.ALL; @@ -35,59 +37,49 @@ USE dp_lib.dp_stream_pkg.ALL; ENTITY st_xsq_mm_to_dp IS GENERIC ( - g_data_size : NATURAL; - g_step_size : NATURAL; - g_nof_data : NATURAL + g_nof_streams : NATURAL; + g_nof_crosslets : NATURAL; + g_nof_signal_inputs : NATURAL; + g_dsp_data_w : NATURAL := 16 ); PORT ( rst : IN STD_LOGIC; clk : IN STD_LOGIC; - start_pulse : IN STD_LOGIC; - mm_done : OUT STD_LOGIC; - mm_mosi : OUT t_mem_mosi; - mm_miso : IN t_mem_miso; - out_sosi : OUT t_dp_sosi; - out_siso : IN t_dp_siso + in_sosi : IN t_dp_sosi; -- sop used as start signal + mm_mosi_arr : OUT t_mem_mosi_arr(g_nof_streams -1 DOWNTO 0); + mm_miso_arr : IN t_mem_miso_arr(g_nof_streams -1 DOWNTO 0); + out_sosi_arr : OUT t_dp_sosi_arr(g_nof_streams -1 DOWNTO 0) ); END st_xsq_mm_to_dp; ARCHITECTURE rtl OF st_xsq_mm_to_dp IS - CONSTANT c_mem_size : NATURAL := g_step_size * g_nof_data; - TYPE t_reg IS RECORD - busy : STD_LOGIC; - sop : STD_LOGIC; - eop : STD_LOGIC; - word_index : NATURAL; - step_index : NATURAL; + in_sosi_strobe : t_dp_sosi; + out_sosi_ctrl : t_dp_sosi; + busy : STD_LOGIC; + crosslets_index : NATURAL; + in_a_index : NATURAL; + in_b_index : NATURAL; END RECORD; - CONSTANT c_reg_rst : t_reg := ('0', '0', '0', 0, 0); + CONSTANT c_reg_rst : t_reg := (c_dp_sosi_rst, c_dp_sosi_rst, '0', 0, 0, 0); SIGNAL r : t_reg; SIGNAL nxt_r : t_reg; - SIGNAL mm_address : NATURAL := 0; - SIGNAL last_mm_address : NATURAL := 0; BEGIN - last_mm_address <= g_step_size * (g_nof_data - 1) + g_data_size + start_address - 1; - mm_address <= start_address + r.word_index + r.step_index; - - mm_mosi.address <= TO_MEM_ADDRESS(mm_address); - - u_sosi : PROCESS(r, mm_miso) + u_sosi : PROCESS(r, mm_miso_arr) BEGIN - out_sosi <= c_dp_sosi_rst; -- To avoid Modelsim warnings on conversion to integer from unused fields. - out_sosi.data <= RESIZE_DP_DATA(mm_miso.rddata(c_word_w-1 DOWNTO 0)); - out_sosi.valid <= mm_miso.rdval; -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so same as the ready latency (RL = 1) - out_sosi.sop <= r.sop; -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.sop can be used for output sop - out_sosi.eop <= r.eop; -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.eop can be used for output eop + FOR I IN 0 TO g_nof_streams-1 LOOP + out_sosi_arr(I) <= r.out_sosi_ctrl; + out_sosi_arr(I).re <= RESIZE_DP_DSP_DATA(mm_miso_arr(I).rddata(g_dsp_data_w-1 DOWNTO 0)); + out_sosi_arr(I).im <= RESIZE_DP_DSP_DATA(mm_miso_arr(I).rddata(c_nof_complex * g_dsp_data_w -1 DOWNTO g_dsp_data_w)); + out_sosi_arr(I).valid <= mm_miso_arr(I).rdval; -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so same as the ready latency (RL = 1) + END LOOP; END PROCESS; - mm_done <= r.eop; - p_reg : PROCESS(rst, clk) BEGIN IF rst='1' THEN @@ -97,40 +89,55 @@ BEGIN END IF; END PROCESS; - p_comb : PROCESS(r, start_pulse, out_siso, mm_address, last_mm_address) + p_comb : PROCESS(r, in_sosi) VARIABLE v : t_reg; BEGIN v := r; - v.sop := '0'; - v.eop := '0'; - mm_mosi.rd <= '0'; - IF r.busy = '0' AND start_pulse = '1' THEN + v.out_sosi_ctrl := c_dp_sosi_rst; + FOR I IN 0 TO g_nof_streams-1 LOOP + mm_mosi_arr(I).rd <= '0'; + END LOOP; + + IF r.busy = '0' AND in_sosi.sop = '1' THEN -- initiate next block v.busy := '1'; + v.in_sosi_strobe := in_sosi; ELSIF r.busy = '1' THEN - IF out_siso.ready = '1' THEN - -- continue with block - mm_mosi.rd <= '1'; - IF r.word_index < g_data_size - 1 THEN - v.word_index := r.word_index + 1; + -- continue with block + FOR I IN 0 TO g_nof_streams-1 LOOP + mm_mosi_arr(I).rd <= '1'; + mm_mosi_arr(I).address <= TO_MEM_ADDRESS(r.crosslets_index * g_nof_signal_inputs + r.in_b_index); -- streams iterate over in_b_index + END LOOP; + + -- Counters + IF r.in_b_index < g_nof_signal_inputs - 1 THEN + v.in_b_index := r.in_b_index + 1; + ELSE + v.in_b_index := 0; + IF r.in_a_index < g_nof_signal_inputs - 1 THEN + v.in_a_index := r.in_a_index + 1; ELSE - v.word_index := 0; - v.step_index := r.step_index + g_step_size; - END IF; - - -- check start of block - IF r.word_index = 0 AND r.step_index = 0 THEN - v.sop := '1'; - END IF; - - -- check end of block - IF mm_address >= last_mm_address THEN - v.eop := '1'; - -- prepare for next block - v.busy := '0'; - v.word_index := 0; - v.step_index := 0; - END IF; + v.in_a_index := 0; + IF r.crosslets_index < g_nof_crosslets - 1 THEN + v.crosslets_index := r.crosslets_index + 1; + ELSE + v.crosslets_index := 0; + END IF; + END IF; + END IF; + + -- check start of block + IF r.crosslets_index = 0 AND r.in_a_index = 0 AND r.in_b_index = 0 THEN + v.out_sosi_ctrl.sop := '1'; + v.out_sosi_ctrl.sync := r.in_sosi_strobe.sync; + v.out_sosi_ctrl.bsn := r.in_sosi_strobe.bsn; + END IF; + + -- check end of block + IF r.crosslets_index >= (g_nof_crosslets - 1) AND r.in_a_index >= (g_nof_signal_inputs - 1) AND r.in_b_index >= (g_nof_signal_inputs - 1) THEN + v.out_sosi_ctrl.eop := '1'; + v.out_sosi_ctrl.err := r.in_sosi_strobe.err; + v.busy := '0'; END IF; END IF; nxt_r <= v; diff --git a/libraries/dsp/st/src/vhdl/st_xst.vhd b/libraries/dsp/st/src/vhdl/st_xst.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f7d7d37e7f091fb031e8aa7822341f131c382bdb --- /dev/null +++ b/libraries/dsp/st/src/vhdl/st_xst.vhd @@ -0,0 +1,188 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- +-- Author : R. vd Walle +-- Purpose: +-- Calculate Crosslets Statistics +-- Description: +-- Consists of st_xsq_mm_to_dp connected to st_xsq_arr. in_b_arr comes directly +-- from st_xsq_mm_to_dp but all streams in in_a_arr are x_sosi_arr(0) with corrected +-- indices done by a process. +-- Remarks: +-- . More detail, see: +-- https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+Correlator +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, mm_lib, technology_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +ENTITY st_xst IS + GENERIC ( + g_nof_streams : NATURAL := 1; + g_nof_crosslets : NATURAL := 1; + g_nof_signal_inputs : NATURAL := 2; + g_in_data_w : NATURAL := 18; -- width of the data to be accumulated + g_stat_data_w : NATURAL := 54; -- statistics accumulator width + g_stat_data_sz : NATURAL := 2 -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + + -- Streaming + in_sosi : IN t_dp_sosi; + + -- DP Memory Mapped + mm_mosi_arr : OUT t_mem_mosi_arr(g_nof_streams -1 DOWNTO 0); + mm_miso_arr : IN t_mem_miso_arr(g_nof_streams -1 DOWNTO 0); + + -- MM Memory Mapped + ram_st_xsq_mosi : IN t_mem_mosi; + ram_st_xsq_miso : OUT t_mem_miso + ); +END st_xst; + +ARCHITECTURE str OF st_xst IS + + CONSTANT c_xsq : NATURAL := g_nof_signal_inputs * g_nof_signal_inputs; + CONSTANT c_nof_statistics : NATURAL := g_nof_crosslets * c_xsq; + CONSTANT c_nof_word : NATURAL := g_stat_data_sz*c_nof_statistics*c_nof_complex; + CONSTANT c_nof_word_w : NATURAL := ceil_log2(c_nof_word); + + TYPE t_reg IS RECORD + busy : STD_LOGIC; + in_a_index : NATURAL; + in_b_index : NATURAL; + END RECORD; + + CONSTANT c_reg_rst : t_reg := ('0', 0, 0); + + SIGNAL r : t_reg; + SIGNAL nxt_r : t_reg; + + SIGNAL in_a_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL in_b_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL x_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL reg_x_sosi_0_re : t_slv_64_arr(g_nof_signal_inputs-1 DOWNTO 0); + SIGNAL reg_x_sosi_0_im : t_slv_64_arr(g_nof_signal_inputs-1 DOWNTO 0); +BEGIN + + st_xsq_mm_to_dp : ENTITY work.st_xsq_mm_to_dp + GENERIC MAP( + g_nof_streams => g_nof_streams, + g_nof_crosslets => g_nof_crosslets, + g_nof_signal_inputs => g_nof_signal_inputs, + g_dsp_data_w => g_in_data_w + ) + PORT MAP( + rst => dp_rst, + clk => dp_clk, + in_sosi => in_sosi, + mm_mosi_arr => mm_mosi_arr, + mm_miso_arr => mm_miso_arr, + out_sosi_arr => x_sosi_arr + ); + + -- rewire + in_b_sosi_arr <= x_sosi_arr; + reg_x_sosi_0_re(nxt_r.in_b_index) <= x_sosi_arr(0).re; + reg_x_sosi_0_im(nxt_r.in_b_index) <= x_sosi_arr(0).im; + + p_in_a : PROCESS(x_sosi_arr, reg_x_sosi_0_re, reg_x_sosi_0_im, nxt_r.in_a_index) + BEGIN + FOR I IN 0 TO g_nof_streams-1 LOOP + in_a_sosi_arr(I) <= x_sosi_arr(0); + in_a_sosi_arr(I).re <= reg_x_sosi_0_re(nxt_r.in_a_index); + in_a_sosi_arr(I).im <= reg_x_sosi_0_im(nxt_r.in_a_index); + END LOOP; + END PROCESS; + + p_reg : PROCESS(dp_rst, dp_clk) + BEGIN + IF dp_rst='1' THEN + r <= c_reg_rst; + ELSIF rising_edge(dp_clk) THEN + r <= nxt_r; + END IF; + END PROCESS; + + p_comb : PROCESS(r, x_sosi_arr) + VARIABLE v : t_reg; + BEGIN + v := r; + + IF r.busy = '0' AND x_sosi_arr(0).sop = '1' THEN + -- initiate next block + v.busy := '1'; + ELSIF r.busy = '1' THEN + -- Counters + IF r.in_b_index < g_nof_signal_inputs - 1 THEN + v.in_b_index := r.in_b_index + 1; + ELSE + v.in_b_index := 0; + IF r.in_a_index < g_nof_signal_inputs - 1 THEN + v.in_a_index := r.in_a_index + 1; + ELSE + v.in_a_index := 0; + END IF; + END IF; + END IF; + IF x_sosi_arr(0).eop = '1' THEN + v.busy := '0'; + v.in_a_index := 0; + v.in_b_index := 0; + END IF; + nxt_r <= v; + END PROCESS; + + + -- st_xsq instances + st_xsq_arr : ENTITY work.st_xsq_arr + GENERIC MAP ( + g_nof_streams => g_nof_streams, + g_nof_crosslets => g_nof_crosslets, + g_nof_signal_inputs => g_nof_signal_inputs, + g_in_data_w => g_in_data_w, + g_stat_data_w => g_stat_data_w, + g_stat_data_sz => g_stat_data_sz + ) + PORT MAP ( + + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- Streaming + in_a_arr => in_a_sosi_arr, + in_b_arr => in_b_sosi_arr, + + -- Memory Mapped + ram_st_xsq_mosi => ram_st_xsq_mosi, + ram_st_xsq_miso => ram_st_xsq_miso + ); + + +END str; diff --git a/libraries/dsp/st/tb/vhdl/tb_st_xst.vhd b/libraries/dsp/st/tb/vhdl/tb_st_xst.vhd new file mode 100644 index 0000000000000000000000000000000000000000..62e4513c04c50a6e240826486215820230b3b0f1 --- /dev/null +++ b/libraries/dsp/st/tb/vhdl/tb_st_xst.vhd @@ -0,0 +1,280 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author : R vd Walle +-- Purpose: Testbench for the st_xst unit. +-- +-- Usage in non-auto-mode (c_modelsim_start = 0 in python): +-- > as 5 +-- > run -all +-- Description: +-- The tb generates random data to feed into st_xst. The output is compared to +-- a pre-calculated expected array of xsq values. +-- Remark: +-- . More detail can be found in: +-- https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+Correlator + +LIBRARY IEEE, common_lib, mm_lib, diag_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_math_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 common_lib.common_lfsr_sequences_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 dp_lib.tb_dp_pkg.ALL; +USE work.tb_st_pkg.ALL; + +ENTITY tb_st_xst IS + GENERIC( + g_nof_streams : NATURAL := 9; + g_nof_crosslets : NATURAL := 2; + g_nof_signal_inputs : NATURAL := 12; + g_in_data_w : NATURAL := 16; + g_nof_sync : NATURAL := 3; + g_stat_data_w : NATURAL := 64; -- statistics accumulator width + g_stat_data_sz : NATURAL := 2; -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words + g_nof_block_per_sync : NATURAL := 5; + g_nof_clk_per_blk : NATURAL := 1024 + ); +END tb_st_xst; + +ARCHITECTURE tb OF tb_st_xst IS + + CONSTANT c_sim : BOOLEAN := TRUE; + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_block_size : NATURAL := g_nof_crosslets * g_nof_signal_inputs; + CONSTANT c_random_data_w : NATURAL := 8; + CONSTANT c_xsq : NATURAL := g_nof_signal_inputs * g_nof_signal_inputs; + CONSTANT c_nof_statistics : NATURAL := g_nof_crosslets * c_xsq; + CONSTANT c_nof_statistics_w : NATURAL := ceil_log2(c_nof_statistics); + CONSTANT c_nof_statistics_mem_size : NATURAL := c_nof_complex * 2**c_nof_statistics_w; + CONSTANT c_single_stream_mem_size : NATURAL := c_nof_complex * c_nof_statistics * g_stat_data_sz; + CONSTANT c_total_mem_size : NATURAL := g_nof_streams * c_nof_statistics_mem_size * g_stat_data_sz; + CONSTANT c_random_seed : NATURAL := 100; + + CONSTANT c_mm_ram : t_c_mem := (latency => 1, + adr_w => ceil_log2(c_block_size), + dat_w => c_nof_complex * g_in_data_w, + nof_dat => c_block_size, + init_sl => '0'); -- MM side : sla_in, sla_out + + TYPE t_random_in_2arr IS ARRAY (INTEGER RANGE <>) OF t_integer_arr(0 TO c_block_size-1); + TYPE t_xsq_2arr IS ARRAY (INTEGER RANGE <>) OF t_integer_arr(0 TO c_nof_statistics * c_nof_complex-1); + TYPE t_xsq_out_2arr IS ARRAY (INTEGER RANGE <>) OF t_slv_32_arr(0 TO c_single_stream_mem_size-1); + + SIGNAL random_in_re_2arr : t_random_in_2arr(0 TO g_nof_streams-1); + SIGNAL random_in_im_2arr : t_random_in_2arr(0 TO g_nof_streams-1); + SIGNAL expected_xsq_2arr : t_xsq_2arr(0 TO g_nof_streams-1); + + ---------------------------------------------------------------------------- + -- Clocks and resets + ---------------------------------------------------------------------------- + CONSTANT c_mm_clk_period : TIME := 100 ps; + CONSTANT c_dp_clk_period : TIME := 5 ns; + + SIGNAL tb_end : STD_LOGIC; + + SIGNAL mm_rst : STD_LOGIC := '1'; + SIGNAL mm_clk : STD_LOGIC := '1'; + + SIGNAL dp_rst : STD_LOGIC; + SIGNAL dp_clk : STD_LOGIC := '1'; + + SIGNAL in_sosi : t_dp_sosi := c_dp_sosi_rst; + + ---------------------------------------------------------------------------- + -- MM buses + ---------------------------------------------------------------------------- + SIGNAL ram_st_xsq_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL ram_st_xsq_miso : t_mem_miso := c_mem_miso_rst; + SIGNAL st_xst_mm_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_mosi_rst); + SIGNAL st_xst_mm_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_miso_rst); + + SIGNAL in_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_mosi_rst); + + ---------------------------------------------------------------------------- + -- Output array + ---------------------------------------------------------------------------- + SIGNAL st_xsq_out_2arr : t_xsq_out_2arr(0 TO g_nof_streams-1) := (OTHERS => (OTHERS => (OTHERS => '0'))); + +BEGIN + -- random input and expected xsq + gen_in_exp : FOR I IN 0 TO g_nof_streams-1 GENERATE + random_in_re_2arr(I) <= common_math_create_random_arr(c_block_size, c_random_data_w, c_random_seed+2*I); + random_in_im_2arr(I) <= common_math_create_random_arr(c_block_size, c_random_data_w, c_random_seed+2*I+1); + expected_xsq_2arr(I) <= func_st_calculate_expected_xsq(random_in_re_2arr(0), random_in_im_2arr(0), random_in_re_2arr(I), random_in_im_2arr(I), g_nof_crosslets, g_nof_block_per_sync); + END GENERATE; + + ---------------------------------------------------------------------------- + -- Clock and reset generation + ---------------------------------------------------------------------------- + mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2; + mm_rst <= '1', '0' AFTER c_mm_clk_period*5; + + dp_clk <= NOT dp_clk OR tb_end AFTER c_dp_clk_period/2; + dp_rst <= '1', '0' AFTER c_dp_clk_period*5; + + ------------------------------------------------------------------------------ + -- in mosi Stimuli + ------------------------------------------------------------------------------ + gen_p_in_mosi : FOR M IN 0 TO g_nof_streams-1 GENERATE + p_in_mosi : PROCESS + VARIABLE v_ram_arr : t_slv_32_arr(c_block_size-1 DOWNTO 0); + BEGIN + -- write random data to ram + proc_common_wait_until_low(mm_clk, mm_rst); + FOR J IN 0 TO c_block_size-1 LOOP + v_ram_arr(J) := TO_SVEC(random_in_im_2arr(M)(J), g_in_data_w) & TO_SVEC(random_in_re_2arr(M)(J), g_in_data_w); + END LOOP; + proc_mem_write_ram(v_ram_arr, mm_clk, in_mosi_arr(M)); + WAIT; + END PROCESS; + END GENERATE; + + ------------------------------------------------------------------------------ + -- MM Stimuli + ------------------------------------------------------------------------------ + gen_mm_stim : FOR M IN 0 TO g_nof_streams-1 GENERATE + p_mm_stimuli : PROCESS + BEGIN + -- read statistics + FOR I IN 0 TO g_nof_sync -1 LOOP + proc_common_wait_until_lo_hi(dp_clk, in_sosi.sync); + END LOOP; + proc_common_wait_some_cycles(dp_clk, g_nof_clk_per_blk); + proc_common_wait_some_cycles(dp_clk, 20); + proc_common_wait_some_cycles(mm_clk, 2 * M * c_single_stream_mem_size); + proc_mem_read_ram(M*c_nof_statistics_mem_size, c_single_stream_mem_size, mm_clk, ram_st_xsq_mosi, ram_st_xsq_miso, st_xsq_out_2arr(M)); + WAIT; + END PROCESS; + END GENERATE; + + ------------------------------------------------------------------------------ + -- Data blocks + ------------------------------------------------------------------------------ + p_in_sosi : PROCESS + BEGIN + tb_end <= '0'; + in_sosi <= c_dp_sosi_rst; + proc_common_wait_until_low(dp_clk, dp_rst); + + -- Run some sync intervals with DSP counter data for the real and imag fields + WAIT UNTIL rising_edge(dp_clk); + proc_common_wait_some_cycles(dp_clk, 7); + FOR I IN 0 TO g_nof_sync-1 LOOP + in_sosi.sop <= '1'; + in_sosi.eop <= '1'; + in_sosi.sync <= '1'; + proc_common_wait_some_cycles(dp_clk, 1); + in_sosi <= c_dp_sosi_rst; + proc_common_wait_some_cycles(dp_clk, g_nof_clk_per_blk-1); + FOR J IN 0 TO g_nof_block_per_sync-2 LOOP -- provide sop and eop for block reference + in_sosi.sop <= '1'; + in_sosi.eop <= '1'; + proc_common_wait_some_cycles(dp_clk, 1); + in_sosi <= c_dp_sosi_rst; + proc_common_wait_some_cycles(dp_clk, g_nof_clk_per_blk-1); + END LOOP; + END LOOP; + in_sosi <= c_dp_sosi_rst; + proc_common_wait_some_cycles(dp_clk, 100); + tb_end <= '1'; + WAIT; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Verification + ------------------------------------------------------------------------------ + p_verify : PROCESS + BEGIN + proc_common_wait_until_high(mm_clk, ram_st_xsq_miso.rdval); + proc_common_wait_some_cycles(mm_clk, 2* c_total_mem_size + 10); + FOR M IN 0 TO g_nof_streams -1 LOOP + FOR I IN 0 TO c_nof_statistics * c_nof_complex -1 LOOP + ASSERT TO_SINT(st_xsq_out_2arr(M)(g_stat_data_sz * I)) = expected_xsq_2arr(M)(I) REPORT "WRONG XSQ DATA" SEVERITY ERROR; -- Only read low part of statistic + END LOOP; + END LOOP; + WAIT; + END PROCESS; + + + ---------------------------------------------------------------------------- + -- RAM + ---------------------------------------------------------------------------- + gen_ram : FOR I IN 0 TO g_nof_streams-1 GENERATE + u_ram : ENTITY common_lib.common_ram_cr_cw + GENERIC MAP( + g_ram => c_mm_ram + ) + PORT MAP( + wr_rst => mm_rst, + wr_clk => mm_clk, + wr_en => in_mosi_arr(I).wr, + wr_adr => in_mosi_arr(I).address(c_mm_ram.adr_w-1 DOWNTO 0), + wr_dat => in_mosi_arr(I).wrdata(c_mm_ram.dat_w-1 DOWNTO 0), + + rd_rst => dp_rst, + rd_clk => dp_clk, + rd_en => st_xst_mm_mosi_arr(I).rd, + rd_adr => st_xst_mm_mosi_arr(I).address(c_mm_ram.adr_w-1 DOWNTO 0), + rd_dat => st_xst_mm_miso_arr(I).rddata(c_mm_ram.dat_w-1 DOWNTO 0), + rd_val => st_xst_mm_miso_arr(I).rdval + ); + END GENERATE; + + ---------------------------------------------------------------------------- + -- DUT: Device Under Test + ---------------------------------------------------------------------------- + u_dut : ENTITY work.st_xst + GENERIC MAP( + g_nof_streams => g_nof_streams, + g_nof_signal_inputs => g_nof_signal_inputs, + g_nof_crosslets => g_nof_crosslets, + g_in_data_w => g_in_data_w, + g_stat_data_w => g_stat_data_w, + g_stat_data_sz => g_stat_data_sz + ) + PORT MAP( + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- Streaming + in_sosi => in_sosi, + + -- DP Memory Mapped + mm_mosi_arr => st_xst_mm_mosi_arr, + mm_miso_arr => st_xst_mm_miso_arr, + + -- Memory Mapped + ram_st_xsq_mosi => ram_st_xsq_mosi, + ram_st_xsq_miso => ram_st_xsq_miso + ); + +END tb; diff --git a/libraries/dsp/st/tb/vhdl/tb_tb_st_xst.vhd b/libraries/dsp/st/tb/vhdl/tb_tb_st_xst.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e62c61e10c32fe8cfa0d2a604f2c8cf3bbd4a9ee --- /dev/null +++ b/libraries/dsp/st/tb/vhdl/tb_tb_st_xst.vhd @@ -0,0 +1,60 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author : R vd Walle +-- Purpose: Test multiple instances of tb_st_xst +-- Usage: +-- > as 10 +-- > run -all +-- +-- Description: See tb_st_xst + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; + +ENTITY tb_tb_st_xst IS +END tb_tb_st_xst; + +ARCHITECTURE tb OF tb_tb_st_xst IS + + CONSTANT c_nof_sync : NATURAL := 3; + CONSTANT c_dsp_data_w : NATURAL := 16; + SIGNAL tb_end : STD_LOGIC := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' + +BEGIN +-- GENERICS: +-- g_nof_streams : NATURAL := 9; +-- g_nof_crosslets : NATURAL := 2; +-- g_nof_signal_inputs : NATURAL := 12; +-- g_in_data_w : NATURAL := 16; +-- g_nof_sync : NATURAL := 3; +-- g_stat_data_w : NATURAL := 64; -- statistics accumulator width +-- g_stat_data_sz : NATURAL := 2; -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words +-- g_nof_block_per_sync : NATURAL := 5; +-- g_nof_clk_per_blk : NATURAL := 1024 + + u_sdp : ENTITY work.tb_st_xst GENERIC MAP (9, 1, 12, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024); + u_sdp_one : ENTITY work.tb_st_xst GENERIC MAP (1, 1, 12, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024); + u_sdp_mult_crosslets : ENTITY work.tb_st_xst GENERIC MAP (9, 7, 12, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024); + -- Note: u_max shows that the dut will skip sync periods if nof_statistics is not < g_nof_clk_per_blk + u_max : ENTITY work.tb_st_xst GENERIC MAP (2, 16, 8, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024); -- g_nof_crosslets * g_nof_signal_inputs**2 = 16 * 8 * 8 = 1024 = g_nof_clk_per_blk + +END tb;