diff --git a/applications/lofar2/libraries/sdp/hdllib.cfg b/applications/lofar2/libraries/sdp/hdllib.cfg index 97a713a2e7a5ee6c639742c4d31f72639ebc19f5..843a49247a740b06c32a726543192f50f3590cc8 100644 --- a/applications/lofar2/libraries/sdp/hdllib.cfg +++ b/applications/lofar2/libraries/sdp/hdllib.cfg @@ -14,6 +14,7 @@ synth_files = src/vhdl/sdp_info.vhd src/vhdl/sdp_beamformer_output.vhd src/vhdl/sdp_statistics_offload.vhd + src/vhdl/sdp_crosslets_subband_select.vhd src/vhdl/node_sdp_adc_input_and_timing.vhd src/vhdl/node_sdp_filterbank.vhd src/vhdl/node_sdp_beamformer.vhd @@ -21,10 +22,12 @@ synth_files = test_bench_files = tb/vhdl/tb_sdp_info.vhd tb/vhdl/tb_sdp_statistics_offload.vhd + tb/vhdl/tb_sdp_crosslets_subband_select.vhd regression_test_vhdl = tb/vhdl/tb_sdp_info.vhd tb/vhdl/tb_sdp_statistics_offload.vhd + tb/vhdl/tb_sdp_crosslets_subband_select.vhd [modelsim_project_file] diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_crosslets_subband_select.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_crosslets_subband_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..5400b70e891a44d1835da0be6150ebb100f02824 --- /dev/null +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_crosslets_subband_select.vhd @@ -0,0 +1,325 @@ +------------------------------------------------------------------------------- +-- +-- 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. van der Walle +-- Purpose: +-- Select subbands from incoming blocks +-- Description: +-- The Crosslet subband select selects N_crosslets from each incoming block. Per +-- crosslet there are S_pn = 12 subbands, one from each signal input of the PN. +-- Remark: +-- . See L5 SDPFW Design Document: Subband Correlator +-- Link: https://support.astron.nl/confluence/pages/viewpage.action?spaceKey=L2M&title=L5+SDPFW+Design+Document%3A+Subband+Correlator +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, reorder_lib, st_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE work.sdp_pkg.ALL; + +ENTITY sdp_crosslets_subband_select IS + GENERIC ( + g_N_crosslets : NATURAL := c_sdp_N_crosslets + ); + PORT ( + dp_clk : IN STD_LOGIC; + dp_rst : IN STD_LOGIC; + + in_sosi_arr : IN t_dp_sosi_arr(c_sdp_P_pfb-1 DOWNTO 0); + out_sosi : OUT t_dp_sosi; + + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + reg_crosslets_info_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_crosslets_info_miso : OUT t_mem_miso := c_mem_miso_rst; + + reg_bsn_scheduler_xsub_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_bsn_scheduler_xsub_miso : OUT t_mem_miso := c_mem_miso_rst; + + out_crosslets_info : OUT STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) + + ); +END sdp_crosslets_subband_select; + +ARCHITECTURE str OF sdp_crosslets_subband_select IS + + + CONSTANT c_crosslets_info_dly : NATURAL := 1; + CONSTANT c_row_select_slv_w : NATURAL := ceil_log2(c_sdp_P_pfb); + CONSTANT c_row_select_pipeline : NATURAL := 1; + CONSTANT c_out_sosi_pipeline : NATURAL := 1; + + TYPE t_crosslets_control_reg IS RECORD -- local registers + offset_index : NATURAL; + row_index : NATURAL; + col_index : NATURAL; + step : NATURAL RANGE 0 TO c_sdp_N_sub-1; + offsets : t_natural_arr(g_N_crosslets-1 DOWNTO 0); + started : STD_LOGIC; + row_select_slv : STD_LOGIC_VECTOR(c_row_select_slv_w-1 DOWNTO 0); + col_select_mosi : t_mem_mosi; + sync_detected : STD_LOGIC; + END RECORD; + + CONSTANT c_reg_rst : t_crosslets_control_reg := ( 0, 0, 0, 0, (OTHERS => 0), '0', (OTHERS => '0'), c_mem_mosi_rst, '0'); + + -- Define the local registers in t_crosslets_control_reg record + SIGNAL r : t_crosslets_control_reg; + SIGNAL nxt_r : t_crosslets_control_reg; + + SIGNAL start_trigger : STD_LOGIC := '0'; + + SIGNAL col_select_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL col_select_miso : t_mem_miso := c_mem_miso_rst; + SIGNAL row_select_slv : STD_LOGIC_VECTOR(c_row_select_slv_w-1 DOWNTO 0); + + SIGNAL col_sosi_arr : t_dp_sosi_arr(c_sdp_P_pfb-1 DOWNTO 0); + SIGNAL row_sosi : t_dp_sosi; + + SIGNAL crosslets_info_reg : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL active_crosslets_info : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := (OTHERS => '0'); +BEGIN + + --------------------------------------------------------------- + -- BSN scheduler + --------------------------------------------------------------- + u_bsn_scheduler : ENTITY dp_lib.mms_dp_bsn_scheduler + GENERIC MAP ( + g_cross_clock_domain => TRUE, + g_bsn_w => c_dp_stream_bsn_w + ) + PORT MAP ( + -- Memory-mapped clock domain + mm_rst => mm_rst, + mm_clk => mm_clk, + + reg_mosi => reg_bsn_scheduler_xsub_mosi, + reg_miso => reg_bsn_scheduler_xsub_miso, + + -- Streaming clock domain + dp_rst => dp_rst, + dp_clk => dp_clk, + + snk_in => in_sosi_arr(0), -- only uses eop (= block sync), bsn[] + trigger_out => start_trigger + ); + + --------------------------------------------------------------- + -- Crosslets info + --------------------------------------------------------------- + u_crosslets_info : ENTITY common_lib.mms_common_reg + GENERIC MAP( + g_mm_reg => c_sdp_mm_reg_crosslets_info + ) + PORT MAP( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => dp_rst, + st_clk => dp_clk, + + -- MM bus access in memory-mapped clock domain + reg_mosi => reg_crosslets_info_mosi, + reg_miso => reg_crosslets_info_miso, + + in_reg => crosslets_info_reg, + out_reg => crosslets_info_reg + ); + + --------------------------------------------------------------- + -- Crosslets control process + --------------------------------------------------------------- + p_regs_crosslets_control : 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_crosslets_control : PROCESS(r, start_trigger, crosslets_info_reg, in_sosi_arr, col_select_miso) + VARIABLE v : t_crosslets_control_reg; + VARIABLE v_offsets : t_natural_arr(g_N_crosslets-1 DOWNTO 0); -- Use extra variable to simplify col_select_mosi address selection + BEGIN + v := r; + v.col_select_mosi := c_mem_mosi_rst; + + -- start/restart + IF start_trigger = '1' THEN + v.started := '1'; + v.offset_index := 0; + v.row_index := 0; + v.col_index := 0; + v.sync_detected := '0'; + + v.step := TO_UINT(crosslets_info_reg(c_sdp_crosslets_info_reg_w-1 DOWNTO c_sdp_crosslets_info_reg_w - c_sdp_crosslets_index_w)); + FOR I IN 0 TO g_N_crosslets-1 LOOP + v_offsets(I) := TO_UINT(crosslets_info_reg((I+1)*c_sdp_crosslets_index_w-1 DOWNTO I*c_sdp_crosslets_index_w)); + END LOOP; + END IF; + + IF in_sosi_arr(0).sync = '1' AND start_trigger = '0' THEN + v.sync_detected := '1'; + END IF; + + IF r.started = '1' THEN + -- add step to offsets + IF in_sosi_arr(0).eop = '1' AND r.sync_detected = '1' THEN -- change offsets 1 packet after the sync due to the buffered packet in reorder_col_wide_select + v.sync_detected := '0'; + FOR I IN 0 TO g_N_crosslets-1 LOOP + v_offsets(I) := r.offsets(I) + TO_UINT(crosslets_info_reg(c_sdp_crosslets_info_reg_w-1 DOWNTO c_sdp_crosslets_info_reg_w - c_sdp_crosslets_index_w)); + END LOOP; + END IF; + + -- Make col/row selection + IF col_select_miso.waitrequest = '0' THEN + IF r.col_index >= c_sdp_Q_fft-1 THEN + v.col_index := 0; + IF r.row_index >= c_sdp_P_pfb-1 THEN + v.row_index := 0; + IF r.offset_index >= g_N_crosslets-1 THEN + v.offset_index := 0; + ELSE + v.offset_index := r.offset_index+1; + END IF; + ELSE + v.row_index := r.row_index+1; + END IF; + ELSE + v.col_index := r.col_index+1; + END IF; + + v.col_select_mosi.rd := '1'; + v.col_select_mosi.address(c_sdp_crosslets_index_w-1 DOWNTO 0) := TO_UVEC(c_sdp_Q_fft*v_offsets(r.offset_index) + r.col_index, c_sdp_crosslets_index_w); + v.row_select_slv := TO_UVEC(r.row_index, c_row_select_slv_w); + END IF; + END IF; + v.offsets := v_offsets; + nxt_r <= v; + END PROCESS; + + col_select_mosi <= r.col_select_mosi; + -- pipeline to time row select + u_pipe_row_select : ENTITY common_lib.common_pipeline + GENERIC MAP( + g_pipeline => c_row_select_pipeline, + g_in_dat_w => c_row_select_slv_w, + g_out_dat_w => c_row_select_slv_w + ) + PORT MAP( + rst => dp_rst, + clk => dp_clk, + in_dat => r.row_select_slv, + out_dat => row_select_slv + ); + + active_crosslets_info(c_sdp_crosslets_info_reg_w-1 DOWNTO c_sdp_crosslets_info_reg_w - c_sdp_crosslets_index_w) <= TO_UVEC(r.step, c_sdp_crosslets_index_w); + gen_crosslets_info : FOR I IN 0 TO g_N_crosslets-1 GENERATE + active_crosslets_info((I+1)*c_sdp_crosslets_index_w-1 DOWNTO I*c_sdp_crosslets_index_w) <= TO_UVEC(r.offsets(I), c_sdp_crosslets_index_w); + END GENERATE; + + --------------------------------------------------------------- + -- Crosslet Select + --------------------------------------------------------------- + u_reorder_col_wide_select : ENTITY reorder_lib.reorder_col_wide_select + GENERIC MAP ( + g_nof_inputs => c_sdp_P_pfb, + g_dsp_data_w => c_sdp_W_subband, + g_nof_ch_in => c_sdp_N_sub * c_sdp_Q_fft, + g_nof_ch_sel => g_N_crosslets * c_sdp_S_pn + ) + PORT MAP ( + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- Memory Mapped + col_select_mosi => col_select_mosi, + col_select_miso => col_select_miso, + + -- Streaming + input_sosi_arr => in_sosi_arr, + + output_sosi_arr => col_sosi_arr + ); + + u_reorder_row_select : ENTITY reorder_lib.reorder_row_select + GENERIC MAP ( + g_dsp_data_w => c_sdp_W_subband, + g_nof_inputs => c_sdp_P_pfb, + g_nof_outputs => 1, + g_pipeline_in => 0, + g_pipeline_in_m => 1, + g_pipeline_out => 1 + ) + PORT MAP ( + dp_rst => dp_rst, + dp_clk => dp_clk, + + in_select => row_select_slv, + + -- Streaming + input_sosi_arr => col_sosi_arr, + + output_sosi_arr(0) => row_sosi + ); + + + --------------------------------------------------------------- + -- Out Crosslet info pipeline + --------------------------------------------------------------- + -- pipeline for alignment with sync + u_common_pipeline : ENTITY common_lib.common_pipeline + GENERIC MAP( + g_pipeline => c_crosslets_info_dly, + g_in_dat_w => c_sdp_crosslets_info_reg_w, + g_out_dat_w => c_sdp_crosslets_info_reg_w + ) + PORT MAP( + rst => dp_rst, + clk => dp_clk, + in_en => row_sosi.sync, + in_dat => active_crosslets_info, + out_dat => out_crosslets_info + ); + + --------------------------------------------------------------- + -- Out sosi pipeline + --------------------------------------------------------------- + u_dp_pipeline : ENTITY dp_lib.dp_pipeline + GENERIC MAP ( + g_pipeline => c_out_sosi_pipeline + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + -- ST sink + snk_in => row_sosi, + -- ST source + src_out => out_sosi + ); + +END str; diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd index c2914456898e87400450a1f40aca3b31c17f431b..c8eefd48bd2723d3051e9ba45e48ce576924b872 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd @@ -71,6 +71,7 @@ PACKAGE sdp_pkg is -- L3 SDP Decision: SDP Parameter definitions CONSTANT c_sdp_f_adc_MHz : NATURAL := 200; CONSTANT c_sdp_N_beamsets : NATURAL := 2; + CONSTANT c_sdp_N_crosslets : NATURAL := 1; CONSTANT c_sdp_N_fft : NATURAL := 1024; CONSTANT c_sdp_N_pn_lb : NATURAL := 16; CONSTANT c_sdp_N_pol : NATURAL := 2; @@ -170,6 +171,16 @@ PACKAGE sdp_pkg is -- SST UDP offload MM address widths CONSTANT c_sdp_reg_stat_enable_addr_w :NATURAL := 1; + -- XSUB + CONSTANT c_sdp_crosslets_index_w : NATURAL := ceil_log2(c_sdp_N_sub); + CONSTANT c_sdp_mm_reg_crosslets_info : t_c_mem := (latency => 1, + adr_w => 4, + dat_w => c_sdp_crosslets_index_w, + nof_dat => 16, -- 15 offsets + 1 step + init_sl => '0'); + CONSTANT c_sdp_crosslets_info_reg_w : NATURAL := c_sdp_mm_reg_crosslets_info.nof_dat*c_sdp_mm_reg_crosslets_info.dat_w; + + -- 10GbE offload (cep = central processor) CONSTANT c_sdp_cep_eth_src_mac_47_16 : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00228608"; -- 47:16, 15:8 = backplane, 7:0 = node CONSTANT c_sdp_cep_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"C0A8"; -- 31:16, 15:8 = backplane, 7:0 = node + 1 = 192.168.xx.yy diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_crosslets_subband_select.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_crosslets_subband_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..127f1499fa098add9f4dadca0f90ce6c0071c054 --- /dev/null +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_crosslets_subband_select.vhd @@ -0,0 +1,250 @@ +------------------------------------------------------------------------------- +-- +-- 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: Verify sdp_crosslets_subband_select. +-- Usage: +-- > as 10 +-- > run -all +-- * The tb is self stopping and self checking,tb_end will stop the simulation by +-- stopping the clk and thus all toggling. +-- +-- Description: The tb starts the dut by writing a scheduled bsn to the bsn_scheduler +-- via MM. The offsets and step are configured using MM. The dut makes the subband +-- selection based on the MM configuration and N_crosslets. The TB then verifies out_sosi +-- and out_crosslets_info of the dut by comparing it to the expected output. + +LIBRARY IEEE, common_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.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; +USE work.sdp_pkg.ALL; + +ENTITY tb_sdp_crosslets_subband_select IS + +END tb_sdp_crosslets_subband_select; + + +ARCHITECTURE tb OF tb_sdp_crosslets_subband_select IS + + CONSTANT c_clk_period : TIME := 10 ns; + CONSTANT c_mm_clk_period : TIME := 20 ns; + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_nof_sync : NATURAL := 5; + CONSTANT c_nof_block_per_sync : NATURAL := 4; + CONSTANT c_nof_ch_in : NATURAL := 1024; -- nof input words per block, identical for all input streams. + CONSTANT c_dsp_data_w : NATURAL := c_sdp_W_subband; + CONSTANT c_nof_ch_sel_row : NATURAL := c_sdp_P_pfb; + + CONSTANT c_N_crosslets : NATURAL := 2; + CONSTANT c_ch_sel_offsets : t_natural_arr(0 TO c_N_crosslets-1) := (0, 15); + CONSTANT c_nof_ch_sel_col : NATURAL := c_sdp_Q_fft; -- nof of sequential collums to select per row. + CONSTANT c_ch_sel_step : NATURAL := 3; -- offset step size to increase per sync interval + + CONSTANT c_nof_ch_sel : NATURAL := c_N_crosslets*c_nof_ch_sel_col*c_nof_ch_sel_row; + CONSTANT scheduled_bsn : NATURAL := 11; + + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL mm_clk : STD_LOGIC := '1'; + SIGNAL tb_end : STD_LOGIC; + + SIGNAL mm_mosi : t_mem_mosi; + SIGNAL mm_miso : t_mem_miso; + + SIGNAL mm_trigger_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL mm_trigger_miso : t_mem_miso; + + SIGNAL st_en : STD_LOGIC := '1'; + SIGNAL st_siso_arr : t_dp_siso_arr(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + SIGNAL st_sosi_arr : t_dp_sosi_arr(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL exp_sosi : t_dp_sosi := c_dp_sosi_rst; + + SIGNAL bsn : NATURAL := scheduled_bsn-1; + + SIGNAL in_sosi_arr : t_dp_sosi_arr(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + + SIGNAL out_siso_arr : t_dp_siso_arr(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + SIGNAL out_sosi : t_dp_sosi; + + SIGNAL exp_crosslets_info : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL out_crosslets_info : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := (OTHERS => '0'); +BEGIN + + clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; + mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; + rst <= '1', '0' AFTER c_clk_period*7; + + p_select_stimuli : PROCESS + VARIABLE k : NATURAL; + BEGIN + + proc_common_wait_until_low(mm_clk, rst); + proc_common_wait_some_cycles(mm_clk, 50); -- Give dut some time to start + -- BSN Scheduler + proc_mem_mm_bus_wr(0, scheduled_bsn, mm_clk, mm_trigger_miso, mm_trigger_mosi); + proc_mem_mm_bus_wr(1, 0, mm_clk, mm_trigger_miso, mm_trigger_mosi); + + -- crosslet info + FOR I IN 0 TO c_N_crosslets-1 LOOP + proc_mem_mm_bus_wr(I, c_ch_sel_offsets(I), mm_clk, mm_miso, mm_mosi); --offsets + END LOOP; + proc_mem_mm_bus_wr(15, c_ch_sel_step, mm_clk, mm_miso, mm_mosi); --step + WAIT; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Data blocks + ------------------------------------------------------------------------------ + gen_stimuli : FOR K IN 0 TO c_sdp_P_pfb-1 GENERATE + p_st_stimuli : PROCESS + VARIABLE v_re : NATURAL := 0+k*2**5; + VARIABLE v_im : NATURAL := 1+k*2**5; + BEGIN + tb_end <= '0'; + st_sosi_arr(K) <= c_dp_sosi_rst; + proc_common_wait_until_low(clk, rst); + + -- Run some sync intervals with DSP counter data for the real and imag fields + WAIT UNTIL rising_edge(clk); + FOR I IN 0 TO c_nof_sync-1 LOOP + proc_dp_gen_block_data(c_rl, FALSE, c_dsp_data_w, c_dsp_data_w, 0, v_re, v_im, c_nof_ch_in, 0, 0, '1', "0", clk, st_en, st_siso_arr(K), st_sosi_arr(K)); -- next sync + v_re := v_re + c_nof_ch_in; + v_im := v_im + c_nof_ch_in; + FOR J IN 0 TO c_nof_block_per_sync-2 LOOP -- provide sop and eop for block reference + proc_dp_gen_block_data(c_rl, FALSE, c_dsp_data_w, c_dsp_data_w, 0, v_re, v_im, c_nof_ch_in, 0, 0, '0', "0", clk, st_en, st_siso_arr(K), st_sosi_arr(K)); -- no sync + v_re := v_re + c_nof_ch_in; + v_im := v_im + c_nof_ch_in; + END LOOP; + END LOOP; + st_sosi_arr(K) <= c_dp_sosi_rst; + proc_common_wait_some_cycles(clk, c_nof_ch_in); + proc_common_wait_some_cycles(clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + END GENERATE; + + -- Time stimuli + bsn <= bsn + 1 WHEN rising_edge(clk) AND (st_sosi_arr(0).eop='1'); + + -- Add BSN to the ST data + p_in_sosi : PROCESS(st_sosi_arr, bsn) + BEGIN + FOR I IN 0 TO c_sdp_P_pfb-1 LOOP + in_sosi_arr(I) <= st_sosi_arr(I); + in_sosi_arr(I).bsn <= TO_DP_BSN(bsn); + END LOOP; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Verification + ------------------------------------------------------------------------------ + p_generate_exp_data : PROCESS + VARIABLE v_col : NATURAL := 0; + VARIABLE v_row : NATURAL := 0; + VARIABLE v_offset : NATURAL := 0; + VARIABLE v_sync_ix : NATURAL := 0; + VARIABLE v_k : NATURAL := 0; + BEGIN + FOR I IN 0 TO c_nof_sync*c_nof_block_per_sync-1 LOOP + v_sync_ix := I / c_nof_block_per_sync; + exp_sosi <= c_dp_sosi_rst; + WAIT UNTIL rising_edge(out_sosi.sop); + + exp_crosslets_info(c_sdp_crosslets_info_reg_w-1 DOWNTO c_sdp_crosslets_info_reg_w - c_sdp_crosslets_index_w) <= TO_UVEC(c_ch_sel_step, c_sdp_crosslets_index_w); + FOR C IN 0 TO c_nof_ch_sel_col-1 LOOP + exp_crosslets_info((C+1)*c_sdp_crosslets_index_w-1 DOWNTO C*c_sdp_crosslets_index_w) <= TO_UVEC(c_ch_sel_offsets(C) + v_sync_ix * c_ch_sel_step, c_sdp_crosslets_index_w); + END LOOP; + + FOR J IN 0 TO c_nof_ch_sel-1 LOOP + v_offset := J / (c_nof_ch_sel_col*c_nof_ch_sel_row); + v_col := J MOD c_nof_ch_sel_col; + v_row := (J/c_nof_ch_sel_col) MOD c_nof_ch_sel_row; + v_k := c_nof_ch_sel_col * v_sync_ix * c_ch_sel_step; + + exp_sosi <= c_dp_sosi_rst; + exp_sosi.valid <= '1'; + IF J = 0 THEN + exp_sosi.sop <= '1'; + IF I MOD c_nof_block_per_sync = 0 THEN + exp_sosi.sync <= '1'; + + END IF; + ELSIF j = c_nof_ch_sel-1 THEN + exp_sosi.eop <= '1'; + END IF; + + exp_sosi.re <= TO_DP_DSP_DATA( I * c_nof_ch_in + v_k + c_nof_ch_sel_col*c_ch_sel_offsets(v_offset) + v_col + v_row*2**5); + exp_sosi.im <= TO_DP_DSP_DATA(1+ I * c_nof_ch_in + v_k + c_nof_ch_sel_col*c_ch_sel_offsets(v_offset) + v_col + v_row*2**5); + proc_common_wait_some_cycles(clk, 1); + + END LOOP; + exp_sosi <= c_dp_sosi_rst; + END LOOP; + WAIT; + END PROCESS; + + p_verify_out_data : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + ASSERT out_sosi.valid = exp_sosi.valid REPORT "Wrong out_sosi.valid" SEVERITY ERROR; + ASSERT out_sosi.sop = exp_sosi.sop REPORT "Wrong out_sosi.sop" SEVERITY ERROR; + ASSERT out_sosi.eop = exp_sosi.eop REPORT "Wrong out_sosi.eop" SEVERITY ERROR; + ASSERT out_sosi.sync = exp_sosi.sync REPORT "Wrong out_sosi.sync" SEVERITY ERROR; + ASSERT out_crosslets_info = exp_crosslets_info REPORT "Wrong out_crosslets_info" SEVERITY ERROR; + IF exp_sosi.valid = '1' THEN + ASSERT out_sosi.re = exp_sosi.re REPORT "Wrong out_sosi.re" SEVERITY ERROR; + ASSERT out_sosi.im = exp_sosi.im REPORT "Wrong out_sosi.im" SEVERITY ERROR; + END IF; + END IF; + END PROCESS; + + u_dut : ENTITY work.sdp_crosslets_subband_select + GENERIC MAP ( + g_N_crosslets => c_N_crosslets + ) + PORT MAP ( + dp_rst => rst, + dp_clk => clk, + + mm_rst => rst, + mm_clk => mm_clk, + + reg_crosslets_info_mosi => mm_mosi, + reg_crosslets_info_miso => mm_miso, + + reg_bsn_scheduler_xsub_mosi => mm_trigger_mosi, + reg_bsn_scheduler_xsub_miso => mm_trigger_miso, + + -- Streaming + in_sosi_arr => in_sosi_arr, + out_sosi => out_sosi, + + out_crosslets_info => out_crosslets_info + ); + +END tb; diff --git a/libraries/base/reorder/hdllib.cfg b/libraries/base/reorder/hdllib.cfg index 26e1cb179894277322c7f8416ab7d4e3a9a71c09..0c4ce6f94ca7807fb3e5ce862cdc3210ba3efa8d 100644 --- a/libraries/base/reorder/hdllib.cfg +++ b/libraries/base/reorder/hdllib.cfg @@ -9,8 +9,11 @@ synth_files = src/vhdl/reorder_retreive.vhd src/vhdl/reorder_store.vhd src/vhdl/reorder_col.vhd + src/vhdl/reorder_col_select.vhd src/vhdl/reorder_col_wide.vhd + src/vhdl/reorder_col_wide_select.vhd src/vhdl/reorder_row.vhd + src/vhdl/reorder_row_select.vhd src/vhdl/reorder_matrix.vhd src/vhdl/reorder_sequencer.vhd src/vhdl/reorder_transpose.vhd @@ -31,11 +34,14 @@ test_bench_files = tb/vhdl/tb_reorder_col.vhd tb/vhdl/tb_tb_reorder_col.vhd tb/vhdl/tb_reorder_col_wide.vhd + tb/vhdl/tb_reorder_col_wide_row_select.vhd + tb/vhdl/tb_tb_reorder_col_wide_row_select.vhd tb/vhdl/tb_mmf_reorder_matrix.vhd tb/vhdl/tb_mmf_reorder_row.vhd tb/vhdl/tb_mms_reorder_rewire.vhd regression_test_vhdl = + tb/vhdl/tb_tb_reorder_col_wide_row_select.vhd # tb/vhdl/tb_tb_reorder_col.vhd -- fails in unb2c diff --git a/libraries/base/reorder/src/vhdl/reorder_col_select.vhd b/libraries/base/reorder/src/vhdl/reorder_col_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..98d47ec1b9f302c2577391798a341d1347a45416 --- /dev/null +++ b/libraries/base/reorder/src/vhdl/reorder_col_select.vhd @@ -0,0 +1,228 @@ +------------------------------------------------------------------------------- +-- +-- 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: Reorder block of data in time +-- Description: +-- Select g_nof_ch_sel complex samples from an input block of g_nof_ch_in +-- complex samples. The subband select map is arbitrary (any order and also +-- duplicates) and can be set via the MM interface. +-- The timing of sync and BSN is passed on in parallel. +-- Remarks: +-- . The g_nof_ch_sel can be <= g_nof_ch_in <= period size, where g_nof_ch_in +-- is the number of valid samples from sop to eop. If g_nof_ch_in is equal to +-- the period size then there are no data invalid cycles during a period. +-- Note that if g_nof_ch_in is less than the period size, then g_nof_ch_sel +-- can be larger than g_nof_ch_in to select channels multiple times. +-- . The g_nof_ch_in defines the number of complex input data words in a data +-- period, so 1 complex sample via sosi.im and sosi.re. + +LIBRARY IEEE, common_lib, technology_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; + +ENTITY reorder_col_select IS + GENERIC ( + g_technology : NATURAL := c_tech_select_default; + g_dsp_data_w : NATURAL := 18; + g_nof_ch_in : NATURAL := 1024; + g_nof_ch_sel : NATURAL := 12; -- g_nof_ch_sel < g_nof_ch_in + g_use_complex : BOOLEAN := TRUE + ); + PORT ( + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + + -- Memory Mapped + col_select_mosi : IN t_mem_mosi; -- channel select control on DP clk + col_select_miso : OUT t_mem_miso := c_mem_miso_rst; -- only waitrequest is used + + -- Streaming + input_sosi : IN t_dp_sosi; -- complex input + + output_sosi : OUT t_dp_sosi -- selected complex output with flow control + ); +END reorder_col_select; + + +ARCHITECTURE str OF reorder_col_select IS + + CONSTANT c_store_buf : t_c_mem := (latency => 1, + adr_w => ceil_log2(g_nof_ch_in), + dat_w => c_nof_complex*g_dsp_data_w, + nof_dat => g_nof_ch_in, + init_sl => '0'); -- ST side : stat_mosi + + + CONSTANT c_data_nof_pages : NATURAL := 2; -- fixed dual page SS + CONSTANT c_info_nof_pages : NATURAL := 2; -- fixed, fits the dual page block latency and logic latency of the SS + CONSTANT c_retrieve_lat : NATURAL := c_store_buf.latency + 1; -- = 2 rd_latency from waitrequest + store_buf latency + + SIGNAL info_sop_wr_en : STD_LOGIC_VECTOR(c_info_nof_pages-1 DOWNTO 0); + SIGNAL info_eop_wr_en : STD_LOGIC_VECTOR(c_info_nof_pages-1 DOWNTO 0); + SIGNAL info_sosi : t_dp_sosi; + + SIGNAL store_mosi : t_mem_mosi; + SIGNAL store_done : STD_LOGIC; + + SIGNAL i_col_select_miso : t_mem_miso := c_mem_miso_rst; + + SIGNAL ch_cnt : INTEGER RANGE 0 TO g_nof_ch_sel-1; + SIGNAL nxt_ch_cnt : INTEGER; + SIGNAL retrieve_sosi : t_dp_sosi; + SIGNAL retrieve_en : STD_LOGIC; + SIGNAL retrieve_sop_dly : STD_LOGIC_VECTOR(0 TO c_retrieve_lat); + SIGNAL retrieve_eop_dly : STD_LOGIC_VECTOR(0 TO c_retrieve_lat); + + +BEGIN + + u_store : ENTITY work.reorder_store + GENERIC MAP ( + g_dsp_data_w => g_dsp_data_w, + g_nof_ch_in => g_nof_ch_in, + g_use_complex => g_use_complex + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + -- Streaming + input_sosi => input_sosi, + + -- Timing + store_done => store_done, + + -- Write store buffer control + store_mosi => store_mosi + ); + + u_store_buf : ENTITY common_lib.common_paged_ram_r_w + GENERIC MAP ( + g_technology => g_technology, + g_str => "use_adr", + g_data_w => c_store_buf.dat_w, + g_nof_pages => c_data_nof_pages, + g_page_sz => c_store_buf.nof_dat, + g_wr_start_page => 0, + g_rd_start_page => 1, + g_rd_latency => 1 + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + wr_next_page => store_done, + wr_adr => store_mosi.address(c_store_buf.adr_w-1 DOWNTO 0), + wr_en => store_mosi.wr, + wr_dat => store_mosi.wrdata(c_store_buf.dat_w-1 DOWNTO 0), + rd_next_page => store_done, + rd_adr => col_select_mosi.address(c_store_buf.adr_w-1 DOWNTO 0), + rd_en => col_select_mosi.rd, + rd_dat => i_col_select_miso.rddata(c_store_buf.dat_w-1 DOWNTO 0), + rd_val => i_col_select_miso.rdval + ); + + + -- Enable retrieve when a block has been stored, disable retrieve when the block has been output + u_retrieve_en : ENTITY common_lib.common_switch + GENERIC MAP ( + g_rst_level => '0', + g_priority_lo => FALSE, -- store_done has priority over nxt_retrieve_done when they occur simultaneously + g_or_high => TRUE, + g_and_low => FALSE + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + switch_high => store_done, + switch_low => retrieve_eop_dly(0), + out_level => retrieve_en + ); + + p_reg : PROCESS (dp_clk, dp_rst) + BEGIN + IF dp_rst = '1' THEN + -- Internal registers. + ch_cnt <= 0; + retrieve_sop_dly(1 TO c_retrieve_lat) <= (OTHERS=>'0'); + retrieve_eop_dly(1 TO c_retrieve_lat) <= (OTHERS=>'0'); + ELSIF rising_edge(dp_clk) THEN + -- Internal registers. + ch_cnt <= nxt_ch_cnt; + retrieve_sop_dly(1 TO c_retrieve_lat) <= retrieve_sop_dly(0 TO c_retrieve_lat-1); + retrieve_eop_dly(1 TO c_retrieve_lat) <= retrieve_eop_dly(0 TO c_retrieve_lat-1); + END IF; + END PROCESS; + + p_ch_cnt : PROCESS (retrieve_en, ch_cnt) + BEGIN + nxt_ch_cnt <= ch_cnt; + col_select_miso.waitrequest <= '1'; + + IF retrieve_en='1' THEN + col_select_miso.waitrequest <= '0'; + IF ch_cnt=g_nof_ch_sel-1 THEN + nxt_ch_cnt <= 0; + ELSE + nxt_ch_cnt <= ch_cnt + 1; + END IF; + END IF; + + END PROCESS; + + -- Optional SS output frame control + retrieve_sop_dly(0) <= '1' WHEN retrieve_en='1' AND ch_cnt=0 ELSE '0'; + retrieve_eop_dly(0) <= '1' WHEN retrieve_en='1' AND ch_cnt=g_nof_ch_sel-1 ELSE '0'; + + retrieve_sosi.re <= RESIZE_DP_DSP_DATA(i_col_select_miso.rddata( g_dsp_data_w-1 DOWNTO 0)); + retrieve_sosi.im <= RESIZE_DP_DSP_DATA(i_col_select_miso.rddata(c_nof_complex*g_dsp_data_w-1 DOWNTO g_dsp_data_w)); + retrieve_sosi.data <= RESIZE_DP_DATA(i_col_select_miso.rddata( c_nof_complex*g_dsp_data_w-1 DOWNTO 0)); + retrieve_sosi.valid <= i_col_select_miso.rdval; + retrieve_sosi.sop <= retrieve_sop_dly(c_retrieve_lat) AND i_col_select_miso.rdval; -- Only set sop/eop when valid. + retrieve_sosi.eop <= retrieve_eop_dly(c_retrieve_lat) AND i_col_select_miso.rdval; + -- Page delay the input_sosi info (sync, BSN, channel at sop and err, empty at eop) and combine it with the retrieved SS data to get the output_sosi + info_sop_wr_en <= input_sosi.sop & store_done; + info_eop_wr_en <= input_sosi.eop & store_done; + + u_info_sosi : ENTITY dp_lib.dp_paged_sop_eop_reg + GENERIC MAP ( + g_nof_pages => c_info_nof_pages + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + -- page write enable ctrl + sop_wr_en => info_sop_wr_en, + eop_wr_en => info_eop_wr_en, + -- ST sink + snk_in => input_sosi, + -- ST source + src_out => info_sosi + ); + + output_sosi <= func_dp_stream_combine_info_and_data(info_sosi, retrieve_sosi); + +END str; + diff --git a/libraries/base/reorder/src/vhdl/reorder_col_wide_select.vhd b/libraries/base/reorder/src/vhdl/reorder_col_wide_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..ff0cdce5cab6ef2cb9056e611c3b4063eb00621c --- /dev/null +++ b/libraries/base/reorder/src/vhdl/reorder_col_wide_select.vhd @@ -0,0 +1,100 @@ +------------------------------------------------------------------------------- +-- +-- 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: Select and/or reorder data on multiple streams. +-- +-- Description: +-- Array of reorder_col_select instances +-- +-- Remarks: +-- + +LIBRARY IEEE, common_lib, technology_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; + +ENTITY reorder_col_wide_select IS + GENERIC ( + g_technology : NATURAL := c_tech_select_default; + g_nof_inputs : NATURAL := 6; + g_dsp_data_w : NATURAL := 18; + g_nof_ch_in : NATURAL := 1024; + g_nof_ch_sel : NATURAL := 12; -- g_nof_ch_sel < g_nof_ch_in + g_use_complex : BOOLEAN := TRUE + ); + PORT ( + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + + -- Memory Mapped + col_select_mosi : IN t_mem_mosi; -- channel select control + col_select_miso : OUT t_mem_miso; -- only used for waitrequest + + -- Streaming + input_sosi_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0); -- complex input + input_siso_arr : OUT t_dp_siso_arr(g_nof_inputs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); -- complex input + + output_sosi_arr : OUT t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0) -- selected complex output with flow control + ); +END reorder_col_wide_select; + +ARCHITECTURE str OF reorder_col_wide_select IS + + SIGNAL col_select_miso_arr : t_mem_miso_arr(g_nof_inputs-1 DOWNTO 0); + +BEGIN + + col_select_miso <= col_select_miso_arr(0); -- All inputs have the same mosi/miso + + --------------------------------------------------------------- + -- INSTANTIATE MULTIPLE SINGLE CHANNEL SUBBAND SELECT UNITS + --------------------------------------------------------------- + gen_nof_input : FOR I IN 0 TO g_nof_inputs-1 GENERATE + u_reorder_col_select : ENTITY work.reorder_col_select + GENERIC MAP ( + g_technology => g_technology, + g_dsp_data_w => g_dsp_data_w, + g_nof_ch_in => g_nof_ch_in, + g_nof_ch_sel => g_nof_ch_sel, + g_use_complex => g_use_complex + ) + PORT MAP ( + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- Memory Mapped + col_select_mosi => col_select_mosi, + col_select_miso => col_select_miso_arr(I), + + -- Streaming + input_sosi => input_sosi_arr(I), + + output_sosi => output_sosi_arr(I) + ); + END GENERATE; + +END str; + diff --git a/libraries/base/reorder/src/vhdl/reorder_row_select.vhd b/libraries/base/reorder/src/vhdl/reorder_row_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..b2c8ebf64687c8f32e4c1e4b7267bd5939e7b4b6 --- /dev/null +++ b/libraries/base/reorder/src/vhdl/reorder_row_select.vhd @@ -0,0 +1,153 @@ +------------------------------------------------------------------------------- +-- +-- 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: Subband Select Reordering. +-- +-- Description: For every clock cycle within a frame a different output +-- configuration can be created, based on the available inputs. +-- +-- The in_select input defines the mapping of the inputs to the outputs +-- for a single clock cylce. +-- +-- Remarks: +-- in_select always has to be defined on the same clock cycle as the in_sosi data. + +LIBRARY IEEE, common_lib, technology_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; + +ENTITY reorder_row_select IS + GENERIC ( + g_technology : NATURAL := c_tech_select_default; + g_dsp_data_w : NATURAL := 16; + g_nof_inputs : NATURAL := 8; + g_nof_outputs : NATURAL := 16; + g_pipeline_in : NATURAL := 1; -- pipeline in_data + g_pipeline_in_m : NATURAL := 1; -- pipeline in_data for M-fold fan out + g_pipeline_out : NATURAL := 1 -- pipeline out_data + ); + PORT ( + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + + -- Streaming + input_sosi_arr : IN t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0); + output_sosi_arr : OUT t_dp_sosi_arr(g_nof_outputs-1 DOWNTO 0); + in_select : IN STD_LOGIC_VECTOR(g_nof_outputs*ceil_log2(g_nof_inputs)-1 DOWNTO 0) + ); +END reorder_row_select; + +ARCHITECTURE str OF reorder_row_select IS + + CONSTANT c_tot_pipeline : NATURAL := g_pipeline_in + g_pipeline_in_m + g_pipeline_out; + CONSTANT c_data_w : NATURAL := g_dsp_data_w*c_nof_complex; + + TYPE t_dp_sosi_2arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0); + + TYPE reg_type IS RECORD + pipe_sosi_2arr : t_dp_sosi_2arr(c_tot_pipeline-1 DOWNTO 0); + output_sosi_arr : t_dp_sosi_arr(g_nof_outputs-1 DOWNTO 0); + END RECORD; + + SIGNAL r, rin : reg_type; + + SIGNAL reorder_in_dat : STD_LOGIC_VECTOR(g_nof_inputs*c_data_w-1 DOWNTO 0); + SIGNAL reorder_out_dat : STD_LOGIC_VECTOR(g_nof_outputs*c_data_w-1 DOWNTO 0); + +BEGIN + + --------------------------------------------------------------- + -- PREPARE THE INPUT DATA. + -- + -- Use a delayed version of the input data to correct for the + -- delay that is introduced by the read latency of the + -- selection buffer. + --------------------------------------------------------------- + gen_input : FOR I IN g_nof_inputs-1 DOWNTO 0 GENERATE + reorder_in_dat((I+1)*c_data_w-1 DOWNTO I*c_data_w) <= input_sosi_arr(I).im(g_dsp_data_w-1 DOWNTO 0) & + input_sosi_arr(I).re(g_dsp_data_w-1 DOWNTO 0); + END GENERATE; + + --------------------------------------------------------------- + -- EXECUTE SELECTION + -- + -- Selection is performed based on the setting of the + -- in_select signal. + --------------------------------------------------------------- + u_reorder : ENTITY common_lib.common_select_m_symbols + GENERIC MAP ( + g_nof_input => g_nof_inputs, + g_nof_output => g_nof_outputs, + g_symbol_w => c_data_w, + g_pipeline_in => g_pipeline_in, + g_pipeline_in_m => g_pipeline_in_m, + g_pipeline_out => g_pipeline_out + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + in_data => reorder_in_dat, + in_select => in_select, + out_data => reorder_out_dat + ); + + + --------------------------------------------------------------- + -- REGISTERING AND PIPELINING + -- + -- This process takes care of registering the incoming SOSI + -- array and the pipelining for all SOSI control fields. + -- Also the data-output of the select_m_symbols block is merged + -- here with the rest of the pipelined SOSI signals. + --------------------------------------------------------------- + comb : PROCESS(r, input_sosi_arr, reorder_out_dat) + VARIABLE v : reg_type; + BEGIN + v := r; + v.pipe_sosi_2arr(0) := input_sosi_arr; + v.pipe_sosi_2arr(c_tot_pipeline-1 DOWNTO 1) := r.pipe_sosi_2arr(c_tot_pipeline-2 DOWNTO 0); + + -- Merge data output to the outgoing SOSI record. + FOR I IN g_nof_outputs-1 DOWNTO 0 LOOP + v.output_sosi_arr(I) := r.pipe_sosi_2arr(c_tot_pipeline-1)(0); + v.output_sosi_arr(I).im := RESIZE_DP_DSP_DATA(reorder_out_dat((I+1)*c_data_w-1 DOWNTO I*c_data_w + g_dsp_data_w)); + v.output_sosi_arr(I).re := RESIZE_DP_DSP_DATA(reorder_out_dat((I+1)*c_data_w-g_dsp_data_w-1 DOWNTO I*c_data_w)); + END LOOP; + + rin <= v; + END PROCESS comb; + + regs : PROCESS(dp_clk) + BEGIN + IF rising_edge(dp_clk) THEN + r <= rin; + END IF; + END PROCESS; + + output_sosi_arr <= r.output_sosi_arr; + +END str; + diff --git a/libraries/base/reorder/tb/vhdl/tb_reorder_col_wide_row_select.vhd b/libraries/base/reorder/tb/vhdl/tb_reorder_col_wide_row_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..db63122e71dbd21b911c3b2d160fb819505d1629 --- /dev/null +++ b/libraries/base/reorder/tb/vhdl/tb_reorder_col_wide_row_select.vhd @@ -0,0 +1,324 @@ +------------------------------------------------------------------------------- +-- +-- 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: Verify reorder_col_wide select and reorder_row_select. +-- Usage: +-- > as 10 +-- > run -all +-- * The tb is self stopping and self checking,tb_end will stop the simulation by +-- stopping the clk and thus all toggling. +-- +-- Description: The tb generates counter data for all g_nof_inputs packetized according +-- to g_nof_sync, g_nof_block_per_sync and g_nof_ch_in. Each input stream then passes through +-- reorder_col_wide_select where each stream is reordered according to g_nof_ch_sel_col, +-- g_ch_sel_offsets and g_ch_sel_step. Those streams then enter reorder_row_select. Each output +-- is created by selecting one input at the time based on in_select, this tb always selects the next input (row) +-- in ascending order after g_nof_ch_sel_col elements. Each output has the same selection in this tb. +-- The tb verifies the functionality by generating an expected sosi array and comparing it with the output. +-- The signals verified are sop, eop, valid, sync, re, and im. +-- The example below shows what the expected outputs are based on the default TB generics and the following input. +-- The 6 rows in the table represent the c_nof_inputs = 6 input streams. (A,B), (C,D), etc. represent the +-- g_nof_ch_sel_col = 2 nof sequential collums to select per row. +-- +-- Input: +-- | 0| 1| 2| 3| ...| 32| 33| ...|1022|1023| +-- -+----------------------------------------- +-- 0|A0|B0|A1|B1| ...|A16|B16| ...|A511|B511| +-- -|--+--+--+--+----+---+---+----+----+----+ +-- 1|C0|D0|C1|D1| ...|C16|D16| ...|C511|D511| +-- -|--+--+--+--+----+---+---+----+----+----+ +-- 2|E0|F0|E1|F1| ...|E16|F16| ...|E511|F511| +-- -|--+--+--+--+----+---+---+----+----+----+ +-- 3|G0|H0|G1|H1| ...|G16|H16| ...|G511|H511| +-- -|--+--+--+--+----+---+---+----+----+----+ +-- 4|I0|J0|I1|J1| ...|I16|J16| ...|I511|J511| +-- -|--+--+--+--+----+---+---+----+----+----+ +-- 5|K0|L0|K1|L1| ...|K16|L16| ...|K511|L511| +-- +-- Expected output for each of the g_nof_outputs = 2 output streams in the first sync intercal. You can see that +-- all "0" and all "16" elements are selected from the inputs which is configured by g_ch_sel_offset = (0, 16). +-- The next sync intervals, the offset selection will be (0+i*k, 16+i*k) where i is the sync interval and k is +-- g_ch_sel_step = 3. +-- |A0 B0 C0 D0 E0 F0 G0 H0 I0 J0 K0 L0 A16 B16 C16 D16 E16 F16 G16 H16 I16 J16 K16 L16| + +LIBRARY IEEE, common_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.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; + +ENTITY tb_reorder_col_wide_row_select IS + GENERIC( + g_nof_inputs : NATURAL := 6; -- also nof rows + g_nof_outputs : NATURAL := 2; + g_dsp_data_w : NATURAL := 16; + g_nof_sync : NATURAL := 5; + g_nof_block_per_sync : NATURAL := 4; + g_nof_ch_in : NATURAL := 1024; -- nof input words per block, identical for all input streams. + g_nof_ch_sel_col : NATURAL := 2; -- nof of sequential collums to select per row. + g_nof_ch_sel_offset : NATURAL := 2; -- nof offsets defined + g_ch_sel_offsets : t_natural_arr := (0, 16); + g_ch_sel_step : NATURAL := 3; -- offset step size to increase per sync interval + g_reorder_row_select_pipe_in : NATURAL := 1; + g_reorder_row_select_pipe_in_m : NATURAL := 1; + g_reorder_row_select_pipe_out : NATURAL := 1 + ); +END tb_reorder_col_wide_row_select; + + +ARCHITECTURE tb OF tb_reorder_col_wide_row_select IS + + CONSTANT c_clk_period : TIME := 10 ns; + + CONSTANT c_rl : NATURAL := 1; + CONSTANT c_nof_ch_sel_row : NATURAL := g_nof_inputs; + CONSTANT c_nof_ch_sel : NATURAL := g_nof_ch_sel_offset*g_nof_ch_sel_col*c_nof_ch_sel_row; + CONSTANT c_nof_inputs_w : NATURAL := ceil_log2(g_nof_inputs); + CONSTANT c_in_select_w : NATURAL := g_nof_outputs*c_nof_inputs_w; + CONSTANT c_in_select_dly : NATURAL := 1; + CONSTANT c_ch_sel_offsets : t_natural_arr(0 TO g_nof_ch_sel_offset-1) := g_ch_sel_offsets; + + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL tb_end : STD_LOGIC; + + SIGNAL mm_mosi : t_mem_mosi; + SIGNAL mm_miso : t_mem_miso; + + SIGNAL st_en : STD_LOGIC := '1'; + SIGNAL st_siso_arr : t_dp_siso_arr(g_nof_inputs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + SIGNAL st_sosi_arr : t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL exp_sosi_arr : t_dp_sosi_arr(g_nof_outputs-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL exp_siso_arr : t_dp_siso_arr(g_nof_outputs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + + SIGNAL bsn : NATURAL := 10; + + SIGNAL in_sosi_arr : t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + + SIGNAL out_siso_arr : t_dp_siso_arr(g_nof_inputs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + SIGNAL col_wide_select_sosi_arr : t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0); + SIGNAL out_sosi_arr : t_dp_sosi_arr(g_nof_outputs-1 DOWNTO 0); + SIGNAL dly_out_sosi_arr : t_dp_sosi_arr(g_nof_outputs-1 DOWNTO 0); + + SIGNAL reorder_row_in_select : STD_LOGIC_VECTOR(c_in_select_w-1 DOWNTO 0); + SIGNAL in_select : STD_LOGIC_VECTOR(c_in_select_w-1 DOWNTO 0); + +BEGIN + + clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; + rst <= '1', '0' AFTER c_clk_period*7; + + p_select_stimuli : PROCESS + VARIABLE k : NATURAL; + BEGIN + FOR rep IN 0 TO g_nof_sync*g_nof_block_per_sync-1 LOOP + k := g_nof_ch_sel_col * (rep/g_nof_block_per_sync) * g_ch_sel_step; + mm_mosi <= c_mem_mosi_rst; + proc_common_wait_until_low(clk, mm_miso.waitrequest); + FOR I IN 0 TO g_nof_ch_sel_offset-1 LOOP + FOR row IN 0 TO c_nof_ch_sel_row-1 LOOP + FOR col IN 0 TO g_nof_ch_sel_col-1 LOOP + FOR i_out IN 0 TO g_nof_outputs-1 LOOP + reorder_row_in_select((i_out+1)* c_nof_inputs_w -1 DOWNTO i_out * c_nof_inputs_w) <= TO_UVEC(row, c_nof_inputs_w); + END LOOP; + proc_mem_mm_bus_rd(c_ch_sel_offsets(I)+col+k, clk, mm_mosi); + END LOOP; + END LOOP; + END LOOP; + END LOOP; + WAIT; + END PROCESS; + + u_pipe_in_select : ENTITY common_lib.common_pipeline + GENERIC MAP( + g_pipeline => c_in_select_dly, + g_in_dat_w => c_in_select_w, + g_out_dat_w => c_in_select_w + ) + PORT MAP( + rst => rst, + clk => clk, + in_dat => reorder_row_in_select, + out_dat => in_select + ); + ------------------------------------------------------------------------------ + -- Data blocks + ------------------------------------------------------------------------------ + gen_stimuli : FOR K IN 0 TO g_nof_inputs-1 GENERATE + p_st_stimuli : PROCESS + VARIABLE v_re : NATURAL := 0+k*2**5; + VARIABLE v_im : NATURAL := 1+k*2**5; + BEGIN + tb_end <= '0'; + st_sosi_arr(K) <= c_dp_sosi_rst; + proc_common_wait_until_low(clk, rst); + + -- Run some sync intervals with DSP counter data for the real and imag fields + WAIT UNTIL rising_edge(clk); + FOR I IN 0 TO g_nof_sync-1 LOOP + proc_dp_gen_block_data(c_rl, FALSE, g_dsp_data_w, g_dsp_data_w, 0, v_re, v_im, g_nof_ch_in, 0, 0, '1', "0", clk, st_en, st_siso_arr(K), st_sosi_arr(K)); -- next sync + v_re := v_re + g_nof_ch_in; + v_im := v_im + g_nof_ch_in; + FOR J IN 0 TO g_nof_block_per_sync-2 LOOP -- provide sop and eop for block reference + proc_dp_gen_block_data(c_rl, FALSE, g_dsp_data_w, g_dsp_data_w, 0, v_re, v_im, g_nof_ch_in, 0, 0, '0', "0", clk, st_en, st_siso_arr(K), st_sosi_arr(K)); -- no sync + v_re := v_re + g_nof_ch_in; + v_im := v_im + g_nof_ch_in; + END LOOP; + END LOOP; + st_sosi_arr(K) <= c_dp_sosi_rst; + proc_common_wait_some_cycles(clk, g_nof_ch_in); + proc_common_wait_some_cycles(clk, 10); + tb_end <= '1'; + WAIT; + END PROCESS; + END GENERATE; + + -- Time stimuli + bsn <= bsn + 1 WHEN rising_edge(clk) AND (st_sosi_arr(0).eop='1'); -- OR st_sosi.sync='1'); + + -- Add BSN to the ST data + p_in_sosi : PROCESS(st_sosi_arr, bsn) + BEGIN + FOR I IN 0 TO g_nof_inputs-1 LOOP + in_sosi_arr(I) <= st_sosi_arr(I); + in_sosi_arr(I).bsn <= TO_DP_BSN(bsn); + END LOOP; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Verification + ------------------------------------------------------------------------------ + u_pipeline_arr : ENTITY dp_lib.dp_pipeline_arr + GENERIC MAP ( + g_nof_streams => g_nof_outputs + ) + PORT MAP ( + rst => rst, + clk => clk, + + snk_in_arr => out_sosi_arr, + src_out_arr => dly_out_sosi_arr + ); + + gen_verify : FOR O IN 0 TO g_nof_outputs-1 GENERATE + p_generate_exp_data : PROCESS + VARIABLE v_col : NATURAL := 0; + VARIABLE v_row : NATURAL := 0; + VARIABLE v_offset : NATURAL := 0; + VARIABLE v_sync_ix : NATURAL := 0; + VARIABLE v_k : NATURAL := 0; + BEGIN + FOR I IN 0 TO g_nof_sync*g_nof_block_per_sync-1 LOOP + exp_sosi_arr(O) <= c_dp_sosi_rst; + proc_common_wait_until_high(clk, out_sosi_arr(0).sop); + FOR J IN 0 TO c_nof_ch_sel-1 LOOP + v_sync_ix := I / g_nof_block_per_sync; + v_offset := J / (g_nof_ch_sel_col*c_nof_ch_sel_row); + v_col := J MOD g_nof_ch_sel_col; + v_row := (J/g_nof_ch_sel_col) MOD c_nof_ch_sel_row; + v_k := g_nof_ch_sel_col * v_sync_ix * g_ch_sel_step; + + exp_sosi_arr(O) <= c_dp_sosi_rst; + exp_sosi_arr(O).valid <= '1'; + IF J = 0 THEN + exp_sosi_arr(O).sop <= '1'; + IF I MOD g_nof_block_per_sync = 0 THEN + exp_sosi_arr(O).sync <= '1'; + END IF; + ELSIF j = c_nof_ch_sel-1 THEN + exp_sosi_arr(O).eop <= '1'; + END IF; + + exp_sosi_arr(O).re <= TO_DP_DSP_DATA( I * g_nof_ch_in + v_k + c_ch_sel_offsets(v_offset) + v_col + v_row*2**5); + exp_sosi_arr(O).im <= TO_DP_DSP_DATA(1+ I * g_nof_ch_in + v_k + c_ch_sel_offsets(v_offset) + v_col + v_row*2**5); + proc_common_wait_some_cycles(clk, 1); + END LOOP; + exp_sosi_arr(O) <= c_dp_sosi_rst; + END LOOP; + WAIT; + END PROCESS; + + p_verify_out_sosi : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + ASSERT dly_out_sosi_arr(O).valid = exp_sosi_arr(O).valid REPORT "Wrong out_sosi.valid" SEVERITY ERROR; + ASSERT dly_out_sosi_arr(O).sop = exp_sosi_arr(O).sop REPORT "Wrong out_sosi.sop" SEVERITY ERROR; + ASSERT dly_out_sosi_arr(O).eop = exp_sosi_arr(O).eop REPORT "Wrong out_sosi.eop" SEVERITY ERROR; + ASSERT dly_out_sosi_arr(O).sync = exp_sosi_arr(O).sync REPORT "Wrong out_sosi.sync" SEVERITY ERROR; + IF exp_sosi_arr(O).valid = '1' THEN + ASSERT dly_out_sosi_arr(O).re = exp_sosi_arr(O).re REPORT "Wrong out_sosi.re" SEVERITY ERROR; + ASSERT dly_out_sosi_arr(O).im = exp_sosi_arr(O).im REPORT "Wrong out_sosi.im" SEVERITY ERROR; + END IF; + END IF; + END PROCESS; + END GENERATE; + + + u_dut_col : ENTITY work.reorder_col_wide_select + GENERIC MAP ( + g_nof_inputs => g_nof_inputs, + g_dsp_data_w => g_dsp_data_w, + g_nof_ch_in => g_nof_ch_in, + g_nof_ch_sel => c_nof_ch_sel + ) + PORT MAP ( + dp_rst => rst, + dp_clk => clk, + + -- Memory Mapped + col_select_mosi => mm_mosi, + col_select_miso => mm_miso, + + -- Streaming + input_sosi_arr => in_sosi_arr, + + output_sosi_arr => col_wide_select_sosi_arr + ); + + u_dut_row : ENTITY work.reorder_row_select + GENERIC MAP ( + g_dsp_data_w => g_dsp_data_w, + g_nof_inputs => g_nof_inputs, + g_nof_outputs => g_nof_outputs, + g_pipeline_in => g_reorder_row_select_pipe_in, + g_pipeline_in_m => g_reorder_row_select_pipe_in_m, + g_pipeline_out => g_reorder_row_select_pipe_out + ) + PORT MAP ( + dp_rst => rst, + dp_clk => clk, + + in_select => in_select, + + -- Streaming + input_sosi_arr => col_wide_select_sosi_arr, + + output_sosi_arr => out_sosi_arr + ); + + + +END tb; diff --git a/libraries/base/reorder/tb/vhdl/tb_tb_reorder_col_wide_row_select.vhd b/libraries/base/reorder/tb/vhdl/tb_tb_reorder_col_wide_row_select.vhd new file mode 100644 index 0000000000000000000000000000000000000000..4e499c8e96678ff5ada789594f588ac1ffb2cd43 --- /dev/null +++ b/libraries/base/reorder/tb/vhdl/tb_tb_reorder_col_wide_row_select.vhd @@ -0,0 +1,63 @@ +------------------------------------------------------------------------------- +-- +-- 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_reorder_col_wide_row_select +-- Usage: +-- > as 10 +-- > run -all +-- +-- Description: See tb_reorder_col_wide_row_select + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; + +ENTITY tb_tb_reorder_col_wide_row_select IS +END tb_tb_reorder_col_wide_row_select; + +ARCHITECTURE tb OF tb_tb_reorder_col_wide_row_select 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_inputs : NATURAL := 6; -- also nof rows + -- g_nof_outputs : NATURAL := 2; + -- g_dsp_data_w : NATURAL := 16; + -- g_nof_sync : NATURAL := 5; + -- g_nof_block_per_sync : NATURAL := 4; + -- g_nof_ch_in : NATURAL := 1024; -- nof input words per block, identical for all input streams. + -- g_nof_ch_sel_col : NATURAL := 2; -- nof of sequential collums to select per row. + -- g_nof_ch_sel_offset : NATURAL := 2; -- nof offsets defined + -- g_ch_sel_offsets : t_natural_arr := (0, 16); + -- g_ch_sel_step : NATURAL := 3; -- offset step size to increase per sync interval + -- g_reorder_row_select_pipe_in : NATURAL := 1; + -- g_reorder_row_select_pipe_in_m : NATURAL := 1; + -- g_reorder_row_select_pipe_out : NATURAL := 1 + + u_sdp : ENTITY work.tb_reorder_col_wide_row_select GENERIC MAP (6, 1, c_dsp_data_w, c_nof_sync, 4, 1024, 2, 2, (0, 16), 3, 0, 1, 1); + u_max_out : ENTITY work.tb_reorder_col_wide_row_select GENERIC MAP (8, 1, c_dsp_data_w, c_nof_sync, 1, 512, 8, 8, (0 ,64, 128, 192, 256, 320, 384, 448), 0, 0, 1, 1); -- rows * cols * offsets = 8*8*8 = 512 + u_multiple_out : ENTITY work.tb_reorder_col_wide_row_select GENERIC MAP (2, 5, c_dsp_data_w, c_nof_sync, 4, 1024, 2, 2, (0, 16), 3, 0, 1, 1); + +END tb;