diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index b36341d13bbe15efec73325da5db95dd0be947ee..bde1e5b94e23ef02f8694e5b9065afe70dd5358e 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -160,6 +160,8 @@ synth_files = src/vhdl/dp_block_reshape_sync.vhd src/vhdl/dp_complex_mult.vhd src/vhdl/dp_complex_add.vhd + src/vhdl/dp_selector_arr.vhd + src/vhdl/dp_selector.vhd tb/vhdl/dp_stream_player.vhd tb/vhdl/dp_sosi_recorder.vhd tb/vhdl/dp_stream_rec_play.vhd @@ -293,6 +295,7 @@ test_bench_files = tb/vhdl/tb_tb_tb_dp_backpressure.vhd tb/vhdl/tb_dp_offload_tx_v3.vhd tb/vhdl/tb_dp_offload_rx_filter.vhd + tb/vhdl/tb_dp_selector_arr.vhd regression_test_vhdl = tb/vhdl/tb_dp_fifo_to_mm.vhd @@ -346,7 +349,8 @@ regression_test_vhdl = tb/vhdl/tb_tb_mms_dp_gain_serial_arr.vhd tb/vhdl/tb_tb_dp_throttle_xon.vhd tb/vhdl/tb_tb_dp_xonoff.vhd - + tb/vhdl/tb_dp_selector_arr.vhd + [modelsim_project_file] diff --git a/libraries/base/dp/src/vhdl/dp_selector.vhd b/libraries/base/dp/src/vhdl/dp_selector.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f3eb8790bb103007e06e439bc044b668aaebe37e --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_selector.vhd @@ -0,0 +1,82 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- 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: Single instance wrapper for dp_selector_arr. +-- Description: +-- Remark: +-- . See dp_selector_arr.vhd for more detail. +------------------------------------------------------------------------------- + + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +LIBRARY common_lib, common_mult_lib; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE work.dp_stream_pkg.ALL; + +ENTITY dp_selector IS + GENERIC ( + g_pipeline : NATURAL := 1 + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + dp_rst : IN STD_LOGIC := '0'; + dp_clk : IN STD_LOGIC; + + -- MM interface + reg_selector_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_selector_miso : OUT t_mem_miso; + + pipe_sosi : IN t_dp_sosi; + ref_sosi : IN t_dp_sosi; + out_sosi : OUT t_dp_sosi + ); +END dp_selector; + +ARCHITECTURE str OF dp_selector IS + +BEGIN + + u_dp_selector_arr : ENTITY work.dp_selector_arr + GENERIC MAP ( + g_nof_arr => 1, + g_pipeline => g_pipeline + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + + reg_selector_mosi => reg_selector_mosi, + reg_selector_miso => reg_selector_miso, + + pipe_sosi_arr(0) => pipe_sosi, + ref_sosi_arr(0) => ref_sosi, + out_sosi_arr(0) => out_sosi + ); + +END str; diff --git a/libraries/base/dp/src/vhdl/dp_selector_arr.vhd b/libraries/base/dp/src/vhdl/dp_selector_arr.vhd new file mode 100644 index 0000000000000000000000000000000000000000..5b5f2c8d6c5a5f9eaffb6a545f281e3d6760d036 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_selector_arr.vhd @@ -0,0 +1,133 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- 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: Selects between two input arrays using MM interface. +-- Description: +-- Output is set to pipe_sosi_arr when register is set to '1', output is set +-- to ref_sosi_arr when register is set to '0'. pipe_sosi_arr input can be +-- pipelined, this is configured with the generic "g_pipeline". +-- Remark: +-- The select register is synchronised with the sync signal in ref_sosi_arr. +------------------------------------------------------------------------------- + + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +LIBRARY common_lib, common_mult_lib; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE work.dp_stream_pkg.ALL; + +ENTITY dp_selector_arr IS + GENERIC ( + g_nof_arr : NATURAL := 1; + g_pipeline : NATURAL := 1 + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + dp_rst : IN STD_LOGIC := '0'; + dp_clk : IN STD_LOGIC; + + -- MM interface + reg_selector_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_selector_miso : OUT t_mem_miso; + + pipe_sosi_arr : IN t_dp_sosi_arr(g_nof_arr-1 DOWNTO 0); + ref_sosi_arr : IN t_dp_sosi_arr(g_nof_arr-1 DOWNTO 0); + out_sosi_arr : OUT t_dp_sosi_arr(g_nof_arr-1 DOWNTO 0) + ); +END dp_selector_arr; + +ARCHITECTURE str OF dp_selector_arr IS + CONSTANT c_selector_mem_reg : t_c_mem := (c_mem_reg_rd_latency, 1, 1, 1, '0'); + + SIGNAL reg_selector_en : STD_LOGIC_VECTOR(c_selector_mem_reg.dat_w*c_selector_mem_reg.nof_dat-1 DOWNTO 0); + SIGNAL n_en : STD_LOGIC; + SIGNAL switch_select : STD_LOGIC; + + SIGNAL pipelined_pipe_sosi_arr : t_dp_sosi_arr(g_nof_arr-1 DOWNTO 0); + SIGNAL select_sosi_arr : t_dp_sosi_arr(g_nof_arr-1 DOWNTO 0); + +BEGIN + + u_mms_common_reg : ENTITY common_lib.mms_common_reg + GENERIC MAP ( + g_mm_reg => c_selector_mem_reg + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => dp_rst, + st_clk => dp_clk, + + reg_mosi => reg_selector_mosi, + reg_miso => reg_selector_miso, + + in_reg => reg_selector_en, + out_reg => reg_selector_en + ); + + + n_en <= NOT reg_selector_en(0); + + u_common_switch : ENTITY common_lib.common_switch + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + clken => ref_sosi_arr(0).sync, + switch_high => reg_selector_en(0), + switch_low => n_en, + out_level => switch_select + ); + + + u_pipeline_arr : ENTITY work.dp_pipeline_arr + GENERIC MAP ( + g_nof_streams => g_nof_arr, + g_pipeline => g_pipeline + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + snk_in_arr => pipe_sosi_arr, + src_out_arr => pipelined_pipe_sosi_arr + ); + + + select_sosi_arr <= pipelined_pipe_sosi_arr WHEN switch_select = '1' ELSE ref_sosi_arr; + + u_pipeline_arr_out : ENTITY work.dp_pipeline_arr + GENERIC MAP ( + g_nof_streams => g_nof_arr, + g_pipeline => 1 + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + snk_in_arr => select_sosi_arr, + src_out_arr => out_sosi_arr + ); + +END str; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_selector_arr.vhd b/libraries/base/dp/tb/vhdl/tb_dp_selector_arr.vhd new file mode 100644 index 0000000000000000000000000000000000000000..d49b12b375378f534c8e2608d157a4ace8b7f441 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_selector_arr.vhd @@ -0,0 +1,247 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- 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: +-- Test bench for dp_selector_arr +-- Description: +-- . Two data stream arrays are offered with g_nof_streams=4 to two DUTs. The +-- streams are distinguished by an offset in the data fields, defined by +-- c_pipe_data_offset +-- . One DUT selects one array and the other DUT selects the other array. +-- . The output of the DUTs are compared to the expected output. +-- +-- Usage: +-- > as 10 +-- > run -all +-- +-- Remarks: + +LIBRARY IEEE, common_lib, mm_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE work.dp_stream_pkg.ALL; +USE work.tb_dp_pkg.ALL; + +ENTITY tb_dp_selector_arr IS + GENERIC ( + -- specific + g_in_dat_w : NATURAL := 32; + g_in_nof_words : NATURAL := 1; + g_nof_repeat : NATURAL := 20; + g_pkt_len : NATURAL := 16; -- must be a multiple of g_in_nof_words + g_pkt_gap : NATURAL := 4 + ); +END tb_dp_selector_arr; + +ARCHITECTURE tb OF tb_dp_selector_arr IS + + CONSTANT c_nof_streams : NATURAL := 4; + + CONSTANT c_sync_period : NATURAL := 10; + CONSTANT c_sync_offset : NATURAL := 7; + + CONSTANT c_data_max : UNSIGNED(g_in_dat_w-1 DOWNTO 0) := (OTHERS=>'1'); + CONSTANT c_data_init : INTEGER := -1; + CONSTANT c_bsn_init : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := X"0000000000000000"; -- X"0877665544332211" + CONSTANT c_err_init : NATURAL := 247; + CONSTANT c_channel_init : INTEGER := 5; -- fixed + + CONSTANT c_pipe_data_offset : INTEGER := 1000; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + + SIGNAL stimuli_en : STD_LOGIC := '1'; + SIGNAL stimuli_src_in : t_dp_siso; + SIGNAL stimuli_src_out : t_dp_sosi; + SIGNAL verify_sosi : t_dp_sosi; + + SIGNAL ref_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL pipe_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL out_pipe_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0); + SIGNAL out_ref_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0); + + SIGNAL mm_mosi_pipe : t_mem_mosi; + SIGNAL mm_mosi_ref : t_mem_mosi; + +BEGIN + + + clk <= (NOT clk) OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*7; + + + ------------------------------------------------------------------------------ + -- STREAM CONTROL + ------------------------------------------------------------------------------ + stimuli_en <= '1'; + + ------------------------------------------------------------------------------ + -- DATA GENERATION + ------------------------------------------------------------------------------ + + -- Generate data path input data + p_stimuli_st : PROCESS + VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst; + BEGIN + -- Adjust initial sosi field values by -1 to compensate for auto increment + v_sosi.bsn := INCR_UVEC(c_bsn_init, -1); + v_sosi.channel := INCR_UVEC(TO_DP_CHANNEL(c_channel_init), -1); + v_sosi.data := INCR_UVEC(TO_DP_DATA(c_data_init), -1); + v_sosi.err := INCR_UVEC(TO_DP_ERROR(c_err_init), -1); + + stimuli_src_out <= c_dp_sosi_rst; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 5); + + -- Generate c_nof_repeat packets + FOR I IN 0 TO g_nof_repeat-1 LOOP + -- Auto increment v_sosi field values for this packet + v_sosi.bsn := INCR_UVEC(v_sosi.bsn, 1); + v_sosi.sync := sel_a_b((UNSIGNED(v_sosi.bsn) MOD c_sync_period) = c_sync_offset, '1', '0'); -- insert sync starting at BSN=c_sync_offset and with period c_sync_period + v_sosi.channel := INCR_UVEC(v_sosi.channel, 1); + v_sosi.data := INCR_UVEC(v_sosi.data, g_pkt_len); + v_sosi.data := RESIZE_DP_DATA(v_sosi.data(g_in_dat_w-1 DOWNTO 0)); -- wrap when >= 2**g_in_dat_w + v_sosi.err := INCR_UVEC(v_sosi.err, 1); + + -- Send packet + proc_dp_gen_block_data(g_in_dat_w, TO_UINT(v_sosi.data), g_pkt_len, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, clk, stimuli_en, stimuli_src_in, stimuli_src_out); + + -- Insert optional gap between the packets + proc_common_wait_some_cycles(clk, g_pkt_gap); + END LOOP; + + -- Determine expected sosi field values after end of stimuli + -- . e_qual + v_sosi.bsn := STD_LOGIC_VECTOR( UNSIGNED(c_bsn_init) + g_nof_repeat-1); + v_sosi.channel := TO_DP_CHANNEL(c_channel_init + g_nof_repeat-1); + v_sosi.err := TO_DP_ERROR(c_err_init + g_nof_repeat-1); + -- . account for g_pkt_len + v_sosi.data := INCR_UVEC(v_sosi.data, g_pkt_len-1); + v_sosi.data := RESIZE_DP_DATA(v_sosi.data(g_in_dat_w-1 DOWNTO 0)); -- wrap when >= 2**g_in_dat_w + verify_sosi <= v_sosi; + -- Signal end of stimuli + proc_common_wait_some_cycles(clk, 100); + tb_end <= '1'; + WAIT; + END PROCESS; + + + p_verify : PROCESS + BEGIN + proc_common_wait_some_cycles(clk, g_nof_repeat*(g_pkt_gap+g_pkt_len)); -- Wait until end of simulation. + proc_common_wait_some_cycles(clk, 50); -- latency from stimuli to verify depends on the flow control, so wait sufficiently long for last packet to have passed through + FOR I IN 0 TO c_nof_streams-1 LOOP + ASSERT SIGNED(verify_sosi.channel)=SIGNED(out_ref_sosi_arr(I).channel) REPORT "Unexpected channel from dut_ref output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.channel)=SIGNED(out_pipe_sosi_arr(I).channel) REPORT "Unexpected channel from dut_pipe output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.err)=SIGNED(out_ref_sosi_arr(I).err) REPORT "Unexpected err from dut_ref output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.err)=SIGNED(out_pipe_sosi_arr(I).err) REPORT "Unexpected err from dut_pipe output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.bsn)=SIGNED(out_ref_sosi_arr(I).bsn) REPORT "Unexpected bsn from dut_ref output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.bsn)=SIGNED(out_pipe_sosi_arr(I).bsn) REPORT "Unexpected bsn from dut_pipe output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.data)=SIGNED(out_ref_sosi_arr(I).data) REPORT "Unexpected data from dut_ref output." SEVERITY ERROR; + ASSERT SIGNED(verify_sosi.data)+c_pipe_data_offset=SIGNED(out_pipe_sosi_arr(I).data) REPORT "Unexpected data from dut_pipe output." SEVERITY ERROR; + END LOOP; + WAIT; + END PROCESS; + + stimuli_src_in <= c_dp_siso_rdy; + + gen_connect : FOR I IN 0 TO c_nof_streams-1 generate + ref_sosi_arr(i) <= stimuli_src_out; + END GENERATE; + + -- Add offset to pipe_sosi_arr data to differentiate it from ref_sosi_arr + p_pipe_sosi: PROCESS(stimuli_src_out) + BEGIN + FOR I IN 0 TO c_nof_streams-1 LOOP + pipe_sosi_arr(I) <= stimuli_src_out; + pipe_sosi_arr(I).data <= RESIZE_DP_DATA(INCR_UVEC(stimuli_src_out.data, c_pipe_data_offset)(g_in_dat_w-1 DOWNTO 0)); + END LOOP; + END PROCESS; + + -- DUT that selects pipe_sosi_arr + u_dut_pipe : ENTITY work.dp_selector_arr + GENERIC MAP( + g_nof_arr => c_nof_streams, + g_pipeline => 1 + ) + PORT MAP( + -- Memory-mapped clock domain + mm_rst => rst, + mm_clk => clk, + + reg_selector_mosi => mm_mosi_pipe, + reg_selector_miso => OPEN, + + -- Streaming clock domain + dp_rst => rst, + dp_clk => clk, + + -- ST sinks + pipe_sosi_arr => pipe_sosi_arr, + ref_sosi_arr => ref_sosi_arr, + -- ST source + out_sosi_arr => out_pipe_sosi_arr + ); + + -- DUT that selects ref_sosi_arr + u_dut_ref : ENTITY work.dp_selector_arr + GENERIC MAP( + g_nof_arr => c_nof_streams, + g_pipeline => 1 + ) + PORT MAP( + -- Memory-mapped clock domain + mm_rst => rst, + mm_clk => clk, + + reg_selector_mosi => mm_mosi_ref, + reg_selector_miso => OPEN, + + -- Streaming clock domain + dp_rst => rst, + dp_clk => clk, + + -- ST sinks + pipe_sosi_arr => pipe_sosi_arr, + ref_sosi_arr => ref_sosi_arr, + -- ST source + out_sosi_arr => out_ref_sosi_arr + ); + + p_stim: PROCESS + BEGIN + WAIT UNTIL rst='0'; + proc_mem_mm_bus_wr(0, x"0", clk, mm_mosi_ref); -- select ref_sosi_arr on dut_ref + proc_mem_mm_bus_wr(0, x"1", clk, mm_mosi_pipe); -- select pipe_sosi_arr on dut_pipe + WAIT; + END PROCESS; + +END tb; +