diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd index 6deb4c7bdecfa6063d88f32be59c54745d97c0a1..a925ba49ae0e65c0cc75b49b91ea20e17f00e487 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd @@ -111,6 +111,9 @@ -- are default 0, but in sim the BF weights in node_sdp_beamformer.vhd -- are default unit weights. Therefore also write the BF weight for default -- beamlet 102 to define it value, in case g_beamlet /= 102. +-- * A simulation only section in sdp_beamformer_output.vhd disturbs the BSN, +-- to cause a merged payload error, so that sdp_source_info_payload_error +-- can be verified here. -- -- Usage: -- > as 7 # default @@ -436,6 +439,7 @@ architecture tb of tb_lofar2_unb2c_sdp_station_bf is signal rx_sdp_cep_header : t_sdp_cep_header; signal exp_sdp_cep_header : t_sdp_cep_header; signal exp_dp_bsn : natural; + signal exp_payload_error : std_logic := '0'; -- Beamlets packets data signal rx_beamlet_data : std_logic_vector(c_longword_w - 1 downto 0); -- 64 bit @@ -1245,10 +1249,10 @@ begin -- Prepare exp_sdp_cep_header before rx_beamlet_sosi.eop, so that -- p_verify_cep_header can verify it at rx_beamlet_sosi.eop. - exp_sdp_cep_header <= func_sdp_compose_cep_header(c_exp_ip_header_checksum, c_exp_sdp_info, c_gn_index, + exp_payload_error, c_exp_beamlet_scale, c_exp_beamlet_index, exp_dp_bsn); @@ -1256,15 +1260,39 @@ begin rx_sdp_cep_header <= func_sdp_map_cep_header(rx_hdr_fields_raw); p_verify_cep_header : process - variable v_bool : boolean; + variable v_pkt_cnt : natural; + variable v_new_pkt : boolean; + variable v_error : std_logic := '0'; + variable v_bsn : natural := 0; + variable v_bool : boolean; begin wait until rising_edge(ext_clk); + -- Count packets per beamset + v_pkt_cnt := rx_beamlet_sop_cnt / c_sdp_N_beamsets; + v_new_pkt := rx_beamlet_sop_cnt mod c_sdp_N_beamsets = 0; -- Prepare exp_sdp_cep_header at sop, so that it can be verified at eop if rx_beamlet_sosi.sop = '1' then - -- Expected BSN increments by c_sdp_cep_nof_blocks_per_packet = 4 blocks per packet - if rx_beamlet_sop_cnt mod c_sdp_N_beamsets = 0 then - exp_dp_bsn <= c_init_bsn + (rx_beamlet_sop_cnt / c_sdp_N_beamsets) * c_sdp_cep_nof_blocks_per_packet; + -- Expected BSN increments by c_sdp_cep_nof_blocks_per_packet = 4 blocks per packet, + -- both beamsets are outputting packets. + if v_new_pkt then + -- Default expected + v_error := '0'; + v_bsn := c_init_bsn + v_pkt_cnt * c_sdp_cep_nof_blocks_per_packet; + + -- Expected due to bsn and payload_error stimuli in sdp_beamformer_output.vhd. + if v_pkt_cnt = 1 then + v_error := '1'; + elsif v_pkt_cnt = 2 or v_pkt_cnt = 3 then + v_bsn := v_bsn + 1; + elsif v_pkt_cnt = 4 then + v_bsn := v_bsn + 1; + v_error := '1'; + end if; + + -- Apply expected values + exp_payload_error <= v_error; + exp_dp_bsn <= v_bsn; end if; end if; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd index bf565dbc2ebb961fa6152afc6a1956c31f0008c0..879bc4cfe166f7920a74ea04833ea2cf9a8b4005 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd @@ -105,6 +105,9 @@ -- * The c_wg_phase_offset and c_subband_phase_offset are used to tune the WG -- phase reference to 0.0 degrees at the start (sop) -- * Use g_beamlet_scale = 2**10, for full scale WG and N_ant = 1, see [1] +-- * A simulation only section in sdp_beamformer_output.vhd disturbs the BSN, +-- to cause a merged payload error, so that sdp_source_info_payload_error +-- can be verified here. -- -- Usage: -- > as 7 # default @@ -439,6 +442,7 @@ architecture tb of tb_lofar2_unb2c_sdp_station_bf_ring is signal rx_sdp_cep_header : t_sdp_cep_header; signal exp_sdp_cep_header : t_sdp_cep_header; signal exp_dp_bsn : natural; + signal exp_payload_error : std_logic := '0'; -- Beamlets packets data signal rx_beamlet_data : std_logic_vector(c_longword_w - 1 downto 0); -- 64 bit @@ -577,7 +581,6 @@ begin i_QSFP_0_RX(0) <= i_QSFP_0_TX(c_last_rn); i_QSFP_0_RX(c_last_rn) <= i_QSFP_0_TX(0); - ------------------------------------------------------------------------------ -- CEP model ------------------------------------------------------------------------------ @@ -721,7 +724,6 @@ begin -- END RECORD; -- . Write - for RN in 0 to c_last_rn loop v_gn := g_first_gn + RN; mmf_mm_bus_wr(mmf_unb_file_prefix(v_gn / c_quad, v_gn mod c_quad) & "REG_SDP_INFO", 8, TO_UINT(c_exp_sdp_info.antenna_field_index), tb_clk); @@ -1361,11 +1363,11 @@ begin -- Prepare exp_sdp_cep_header before rx_beamlet_sosi.eop, so that -- p_verify_cep_header can verify it at rx_beamlet_sosi.eop. - exp_sdp_cep_header <= func_sdp_compose_cep_header(c_cep_ip_src_addr, c_exp_ip_header_checksum, c_exp_sdp_info, c_last_gn, + exp_payload_error, c_exp_beamlet_scale, c_exp_beamlet_index, exp_dp_bsn); @@ -1373,15 +1375,39 @@ begin rx_sdp_cep_header <= func_sdp_map_cep_header(rx_hdr_fields_raw); p_verify_cep_header : process - variable v_bool : boolean; + variable v_pkt_cnt : natural; + variable v_new_pkt : boolean; + variable v_error : std_logic := '0'; + variable v_bsn : natural := 0; + variable v_bool : boolean; begin wait until rising_edge(ext_clk); + -- Count packets per beamset + v_pkt_cnt := rx_beamlet_sop_cnt / c_sdp_N_beamsets; + v_new_pkt := rx_beamlet_sop_cnt mod c_sdp_N_beamsets = 0; -- Prepare exp_sdp_cep_header at sop, so that it can be verified at eop if rx_beamlet_sosi.sop = '1' then - -- Expected BSN increments by c_sdp_cep_nof_blocks_per_packet = 4 blocks per packet - if rx_beamlet_sop_cnt mod c_sdp_N_beamsets = 0 then - exp_dp_bsn <= c_init_bsn + (rx_beamlet_sop_cnt / c_sdp_N_beamsets) * c_sdp_cep_nof_blocks_per_packet; + -- Expected BSN increments by c_sdp_cep_nof_blocks_per_packet = 4 blocks per packet, + -- both beamsets are outputting packets. + if v_new_pkt then + -- Default expected + v_error := '0'; + v_bsn := c_init_bsn + v_pkt_cnt * c_sdp_cep_nof_blocks_per_packet; + + -- Expected due to bsn and payload_error stimuli in sdp_beamformer_output.vhd. + if v_pkt_cnt = 1 then + v_error := '1'; + elsif v_pkt_cnt = 2 or v_pkt_cnt = 3 then + v_bsn := v_bsn + 1; + elsif v_pkt_cnt = 4 then + v_bsn := v_bsn + 1; + v_error := '1'; + end if; + + -- Apply expected values + exp_payload_error <= v_error; + exp_dp_bsn <= v_bsn; end if; end if; diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd index 890947c5915a3a28e0ab023f71f4e85f83984e6a..2ba6c2fb7accfbb26a6c290d0e8a277db0ca400c 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd @@ -20,10 +20,12 @@ ------------------------------------------------------------------------------- -- --- Author: R. van der Walle +-- Author: R. van der Walle, E. Kooistra (payload error support) -- Purpose: -- The beamformer output (BDO) packetizes the beamlet data into UDP/IP packets. -- Description: +-- * https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Beamformer +-- * https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Multiple+beamlet+output+destinations -- Remark: -- ------------------------------------------------------------------------------- @@ -73,22 +75,27 @@ entity sdp_beamformer_output is ); end sdp_beamformer_output; - architecture str of sdp_beamformer_output is - constant c_data_w : natural := c_nof_complex * c_sdp_W_beamlet; -- 16b - constant c_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; -- call beamset 'id' and beamlet 'index' + constant c_data_w : natural := c_nof_complex * c_sdp_W_beamlet; -- 16b + constant c_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; -- call beamset 'id' and beamlet 'index' - -- c_fifo_fill must be the exact size of a payload such that no payload gets stuck in the FIFO or the FIFO gets read out too soon. - -- For packets of variable length, dp_fifo_fill_eop must be used. In this case we can use the standard fill fifo. - constant c_fifo_fill : natural := c_sdp_cep_payload_nof_longwords; - constant c_fifo_size : natural := c_fifo_fill * 2; -- Make fifo size large enough for adding header and muxing beamsets. + -- Use c_fifo_fill = c_fifo_size - margin so that FIFO does not get read out too soon. + -- The dp_fifo_fill_eop takes care that the FIFO gets read out whenever there is an + -- eop in the FIFO, so that no payload gets stuck in the FIFO. Thanks to the use of eop + -- it possible to pass on blocks of variable length. + -- Make fifo size large enough for adding header, muxing c_sdp_N_beamsets beamsets and + -- delaying output to be able to realign snk_in.err field from snk_in.eop to src_out.sop. + constant c_fifo_fill : natural := c_sdp_cep_payload_nof_longwords; -- 976 + constant c_fifo_size : natural := true_log_pow2(c_sdp_cep_payload_nof_longwords) * c_sdp_N_beamsets; -- 2048 signal snk_in_concat : t_dp_sosi; - signal dp_packet_merge_src_out : t_dp_sosi; signal dp_repack_data_src_out : t_dp_sosi; - signal dp_fifo_sc_src_out : t_dp_sosi; - signal dp_fifo_sc_src_in : t_dp_siso; + signal dp_packet_merge_src_out : t_dp_sosi; + signal dp_fifo_merge_src_out : t_dp_sosi; + signal dp_fifo_merge_src_in : t_dp_siso; + signal dp_pipeline_src_out : t_dp_sosi; + signal dp_pipeline_src_in : t_dp_siso; signal dp_offload_tx_src_out : t_dp_sosi; signal dp_offload_tx_src_in : t_dp_siso; signal ip_checksum_src_out : t_dp_sosi; @@ -96,12 +103,13 @@ architecture str of sdp_beamformer_output is signal dp_pipeline_ready_src_out : t_dp_sosi; signal dp_pipeline_ready_src_in : t_dp_siso; - signal common_fifo_rd_req : std_logic; + signal dbg_bsn_offset : std_logic; signal payload_err : std_logic_vector(0 downto 0); signal station_info : std_logic_vector(15 downto 0) := (others => '0'); -- Default set all data path driven header fields to 0 signal dp_offload_tx_hdr_fields : std_logic_vector(1023 downto 0) := (others => '0'); + signal dp_offload_tx_header : t_sdp_cep_header; -- to view dp_offload_tx_hdr_fields in Wave window begin @@ -111,15 +119,45 @@ begin -- . send beamlet data big endian with X.re part first, then X.im, Y.re, Y.im ------------------------------------------------------------------------------- p_snk_in_arr : process(in_sosi) + variable v_ref_time : time := 0 ns; begin snk_in_concat <= in_sosi; snk_in_concat.data(c_data_w - 1 downto 0) <= in_sosi.re(c_sdp_W_beamlet - 1 downto 0) & in_sosi.im(c_sdp_W_beamlet - 1 downto 0); + + -- synthesis translate_off + -- Force BSN error in simulation to verify payload error in tb_lofar2_unb2c_sdp_station_bf.vhd, + -- this will cause two times payload errors, one when BSN goes wrong and one when BSN goes ok again. + dbg_bsn_offset <= '0'; + if v_ref_time = 0 ns then + if in_sosi.sop = '1' then + -- Use start of input as reference time, rather than e.g. fixed 50 us, to be + -- independent of how long it takes for the tb to deliver the first block. + v_ref_time := NOW; + -- Offset the v_ref_time to the second block of the c_sdp_cep_nof_blocks_per_packet + -- = 4 blocks that will be merged. + v_ref_time := v_ref_time + c_sdp_block_period * 1 ns; + end if; + elsif NOW > v_ref_time + 1 * c_sdp_cep_nof_blocks_per_packet * c_sdp_block_period * 1 ns and + NOW < v_ref_time + 4 * c_sdp_cep_nof_blocks_per_packet * c_sdp_block_period * 1 ns then + -- Disturb BSN to cause merged payload error. Expected results for the merged blocks: + -- . index 0 : First merged block bsn ok and payload_error = '0'. + -- . index 1 : bsn still ok, but payload error = '1', due to bsn++ after first block + -- . index 2,3 : bsn wrong due to bsn++, but payload error = '0', because all 4 + -- merged blocks have incrementing bsn + -- . index 4 : bsn still wrong due to bsn++, and payload error = '1', because the bsn + -- is restored after first block, so the merged blocks do not have + -- incrementing bsn + -- . index >= 5 : bsn ok and payload_error = '0'. + dbg_bsn_offset <= '1'; + snk_in_concat.bsn <= INCR_UVEC(in_sosi.bsn, 1); + end if; + -- synthesis translate_on end process; ------------------------------------------------------------------------------- -- dp_repack_data -- . 16b -> 64b - -- . We don't need to flow control the source beacause we're going from 16b->64b + -- . We don't need to flow control the source because we're going from 16b->64b ------------------------------------------------------------------------------- u_dp_repack_data : entity dp_lib.dp_repack_data generic map ( @@ -144,7 +182,8 @@ begin ------------------------------------------------------------------------------- u_dp_packet_merge : entity dp_lib.dp_packet_merge generic map( - g_nof_pkt => c_sdp_cep_nof_blocks_per_packet + g_nof_pkt => c_sdp_cep_nof_blocks_per_packet, + g_bsn_increment => 1 ) port map( rst => dp_rst, @@ -159,16 +198,9 @@ begin ------------------------------------------------------------------------------- -- FIFO - -- . We're inserting headers, so dp_offload_tx needs a flow controllable - -- source. - -- . Also, we need a fill FIFO here because 16b->64b will introduce gaps in our - -- TX stream (not allowed by 10G TX MAC). - -- . The fill fifo waits until c_fifo_fill words are received before enabling the - -- output. The total number of words in the fifo is determined by the - -- backpressure. ------------------------------------------------------------------------------- - u_dp_fifo_fill_sc : entity dp_lib.dp_fifo_fill_sc - generic map ( + u_dp_fifo_fill_eop_sc : entity dp_lib.dp_fifo_fill_eop_sc + generic map ( -- pass on dp_packet_merge_src_out.err via u_common_fifo_sc_err g_data_w => c_longword_w, g_empty_w => c_byte_w, g_use_empty => true, @@ -182,28 +214,44 @@ begin port map ( clk => dp_clk, rst => dp_rst, - snk_in => dp_packet_merge_src_out, - - src_out => dp_fifo_sc_src_out, - src_in => dp_fifo_sc_src_in + src_out => dp_fifo_merge_src_out, + src_in => dp_fifo_merge_src_in ); - -- Simple fifo to store the payload error at eop of FIFO input to be used at sop of FIFO output. - -- It can then be used in the packet header. - common_fifo_rd_req <= dp_fifo_sc_src_out.sop; - u_common_fifo_sc : entity common_lib.common_fifo_sc + -- Simple fifo to store the payload error bit at eop of FIFO input to be used at sop of FIFO + -- output, so that payload_err can then be used in the packet header. + -- Typically the u_dp_fifo_fill_eop will store between 0 and c_sdp_N_beamsets = 2 packets. + -- Choose g_nof_words > c_sdp_N_beamsets to have some margin compared to c_fifo_size of the + -- data FIFO. + u_common_fifo_sc_err : entity common_lib.common_fifo_sc generic map ( g_dat_w => 1, - g_nof_words => 2 + g_nof_words => c_sdp_N_beamsets + 2 ) port map ( - rst => dp_rst, - clk => dp_clk, + rst => dp_rst, + clk => dp_clk, wr_dat => dp_packet_merge_src_out.err(0 downto 0), wr_req => dp_packet_merge_src_out.eop, rd_dat => payload_err, - rd_req => common_fifo_rd_req + rd_req => dp_fifo_merge_src_out.sop + ); + + -- Pipeline FIFO output to align payload_err at dp_pipeline_src_out.sop + u_pipeline : entity dp_lib.dp_pipeline + generic map ( + g_pipeline => 1 + ) + port map ( + rst => dp_rst, + clk => dp_clk, + -- ST sink + snk_out => dp_fifo_merge_src_in, + snk_in => dp_fifo_merge_src_out, + -- ST source + src_in => dp_pipeline_src_in, + src_out => dp_pipeline_src_out ); ------------------------------------------------------------------------------- @@ -287,8 +335,10 @@ begin dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_beamlet_index" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_beamlet_index" )) <= TO_UVEC(c_beamlet_index, c_halfword_w); dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_block_period" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_block_period" )) <= sdp_info.block_period; - dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "dp_bsn" ) downto field_lo(c_sdp_cep_hdr_field_arr, "dp_bsn" )) <= dp_fifo_sc_src_out.bsn(63 downto 0); + dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "dp_bsn" ) downto field_lo(c_sdp_cep_hdr_field_arr, "dp_bsn" )) <= dp_pipeline_src_out.bsn(63 downto 0); + -- For viewing the header fields in wave window + dp_offload_tx_header <= func_sdp_map_cep_header(dp_offload_tx_hdr_fields); ------------------------------------------------------------------------------- -- dp_offload_tx_v3 @@ -312,8 +362,8 @@ begin reg_hdr_dat_mosi => reg_hdr_dat_mosi, reg_hdr_dat_miso => reg_hdr_dat_miso, - snk_in_arr(0) => dp_fifo_sc_src_out, - snk_out_arr(0) => dp_fifo_sc_src_in, + snk_in_arr(0) => dp_pipeline_src_out, + snk_out_arr(0) => dp_pipeline_src_in, src_out_arr(0) => dp_offload_tx_src_out, src_in_arr(0) => dp_offload_tx_src_in, diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd index b8866c2a7c796cf94b70c8e66f1d54bd97a0700e..d84f73d36b3aa9e40ad46423df5a9c748285ea2d 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd @@ -64,6 +64,7 @@ package tb_sdp_pkg is ip_header_checksum : natural; sdp_info : t_sdp_info; -- app header gn_index : natural; + payload_error : std_logic; beamlet_scale : natural; beamlet_index : natural; dp_bsn : natural) return t_sdp_cep_header; @@ -71,6 +72,7 @@ package tb_sdp_pkg is function func_sdp_compose_cep_header(ip_header_checksum : natural; sdp_info : t_sdp_info; -- app header gn_index : natural; + payload_error : std_logic; beamlet_scale : natural; beamlet_index : natural; dp_bsn : natural) return t_sdp_cep_header; @@ -283,6 +285,7 @@ package body tb_sdp_pkg is ip_header_checksum : natural; sdp_info : t_sdp_info; -- app header gn_index : natural; + payload_error : std_logic; beamlet_scale : natural; beamlet_index : natural; dp_bsn : natural) return t_sdp_cep_header is @@ -326,7 +329,7 @@ package body tb_sdp_pkg is v_hdr.app.sdp_source_info_nyquist_zone_id := sdp_info.nyquist_zone_index; v_hdr.app.sdp_source_info_f_adc := slv(sdp_info.f_adc); v_hdr.app.sdp_source_info_fsub_type := slv(sdp_info.fsub_type); - v_hdr.app.sdp_source_info_payload_error := TO_UVEC(0, 1); + v_hdr.app.sdp_source_info_payload_error := slv(payload_error); v_hdr.app.sdp_source_info_beam_repositioning_flag := slv(sdp_info.beam_repositioning_flag); v_hdr.app.sdp_source_info_beamlet_width := TO_UVEC(c_sdp_W_beamlet, 4); v_hdr.app.sdp_source_info_gn_id := TO_UVEC(gn_index, 8); @@ -345,6 +348,7 @@ package body tb_sdp_pkg is function func_sdp_compose_cep_header(ip_header_checksum : natural; sdp_info : t_sdp_info; -- app header gn_index : natural; + payload_error : std_logic; beamlet_scale : natural; beamlet_index : natural; dp_bsn : natural) return t_sdp_cep_header is @@ -356,6 +360,7 @@ package body tb_sdp_pkg is ip_header_checksum, sdp_info, gn_index, + payload_error, beamlet_scale, beamlet_index, dp_bsn); diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd index f40db1a79d224bb1622681dedc480ab2684fe5b7..3f2abfd71def8826205ce01c75174837bd53f458 100644 --- a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd +++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd @@ -45,8 +45,10 @@ -- that is a power of 2, so g_fifo_size = true_log_pow2(largest block size + -- c_fifo_tx_fill_margin). -- Remark: --- * The dp_fifo_fill_eop cannot handle continues stream of blocks without a --- gap between blocks it needs 1 cycle to process a block. +-- * The dp_fifo_fill_eop can handle continues stream of blocks without a +-- gap between blocks, as shown by tb_dp_fifo_fill_eop.vhd, because +-- snk_out.ready remains active and the FIFO does not run full. This was +-- fixed by Reinier in Nov 2021 as part of L2SDP-505. -- ------------------------------------------------------------------------------- diff --git a/libraries/base/dp/src/vhdl/dp_packet_merge.vhd b/libraries/base/dp/src/vhdl/dp_packet_merge.vhd index 5e4b1d58d90d7f9cd1608a7a3d935eb1ce099290..551460047fcdcb08626100979c5788b8a1b0ff11 100644 --- a/libraries/base/dp/src/vhdl/dp_packet_merge.vhd +++ b/libraries/base/dp/src/vhdl/dp_packet_merge.vhd @@ -20,11 +20,22 @@ -------------------------------------------------------------------------------- -- Purpose: --- . Merge g_nof_pkt input packets into one output packet +-- . Merge nof_pkt input packets into one output packet. -- Description: +-- . Merge nof_pkt snk_in blocks per src_out block. If nof_pkt = 0 then there +-- is no output. If nof_pkt = 1 then the output is the same as the input. -- . The output is the same as the registered input, except for the SOP and EOP --- signal; these are overridden to create output packets as long as multiple (g_nof_pkt) --- input packets. +-- signal; these are overridden to create output packets as long as multiple +-- (g_nof_pkt) input packets. +-- . Uses bsn of first snk_in block as bsn for merged output src_out block. +-- . The snk_in.err fields of the input blocks are OR-ed to reflect combined +-- error status of the merged blocks in src_out.err of the output block. +-- . When g_bsn_increment = 0 then the snk_in.bsn is not checked. +-- . When g_bsn_increment > 0 then the src_out.err[g_bsn_err_bi] = '1', if +-- the snk_in.bsn did not increment by g_bsn_increment for the merged snk_in +-- blocks in the src_out block. If the bsn increment for the merged blocks is +-- correct, then src_out.err[g_bsn_err_bi] = '0' to indicate that the +-- merged blocks are consecutive, so no input block got lost for this merge. -- -- Remarks: -- . g_nof_pkt statically sets the number of packets to merge into one in absence of @@ -165,7 +176,6 @@ -- . The advantage of this scheme it that it allows designing the function without flow -- control according to scheme A). Then make nxt_r available instead of r and lead nxt_r -- through dp_pipeline to register it and to add the flow control. --- library IEEE,common_lib; use IEEE.std_logic_1164.all; @@ -176,7 +186,9 @@ use work.dp_stream_pkg.all; entity dp_packet_merge is generic ( g_nof_pkt : natural; - g_align_at_sync : boolean := false + g_align_at_sync : boolean := false; + g_bsn_increment : natural := 0; + g_bsn_err_bi : natural := 0 -- bit index (bi) in scr_out.err for snk_in.bsn error ); port ( rst : in std_logic; @@ -202,6 +214,8 @@ architecture rtl of dp_packet_merge is align_cnt : natural range 0 to g_nof_pkt + 1; busy : std_logic; sync : std_logic; + next_bsn : std_logic_vector(c_dp_stream_bsn_w - 1 downto 0); + bsn_err : std_logic; src_out : t_dp_sosi; end record; @@ -224,7 +238,6 @@ begin src_out <= r.src_out; -- can put dp_hold_input here -- - end generate; gen_dp_latency_adapter : if c_use_dp_latency_adapter = true generate @@ -332,18 +345,27 @@ begin if snk_in.sync = '1' then v.src_out.sync := '1'; -- set out sync to '1' if this first block contains the sync. end if; + v.next_bsn := INCR_UVEC(snk_in.bsn, g_bsn_increment); -- expected bsn for next snk_in block + v.bsn_err := '0'; -- bsn of first block is correct by default else if snk_in.sync = '1' then v.sync := '1'; -- Capture sync if it occurs on a pkt_cnt /= 0 so we can use it in the next merged packet end if; + v.next_bsn := INCR_UVEC(r.next_bsn, g_bsn_increment); -- expected bsn for next snk_in block + if unsigned(snk_in.bsn) /= unsigned(r.next_bsn) then + v.bsn_err := '1'; + end if; end if; end if; if snk_in.eop = '1' then if r.pkt_cnt = 0 then - v.src_out.err := snk_in.err; + v.src_out.err := snk_in.err; else - v.src_out.err := r.src_out.err or snk_in.err; -- OR the err fields of the packets to reflect combined error status. + v.src_out.err := r.src_out.err or snk_in.err; -- OR the err fields of the packets to reflect combined error status. + end if; + if g_bsn_increment > 0 then + v.src_out.err(g_bsn_err_bi) := r.bsn_err; -- report bsn error bit in case of missing snk_in block end if; if r.pkt_cnt = r.nof_pkt - 1 then @@ -369,6 +391,8 @@ begin v.align_cnt := 0; v.busy := '0'; v.sync := '0'; + v.next_bsn := (others => '0'); + v.bsn_err := '0'; v.src_out := c_dp_sosi_rst; end if; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd b/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd index 5898e43f38a16626271d535e210c8fb030b967f1..b2ce169ff9463cac24202c5c6cb4f4b5c6385302 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd @@ -47,7 +47,7 @@ use work.tb_dp_pkg.all; entity tb_dp_fifo_fill_eop is generic ( -- Try FIFO settings - g_dut_use_dual_clock : boolean := true; + g_dut_use_dual_clock : boolean := false; g_dut_use_bsn : boolean := false; g_dut_use_empty : boolean := false; g_dut_use_channel : boolean := false; @@ -55,9 +55,10 @@ entity tb_dp_fifo_fill_eop is g_dut_fifo_rl : natural := 1; -- internal RL, use 0 for look ahead FIFO, default 1 for normal FIFO g_dut_fifo_size : natural := 128; g_dut_fifo_fill : natural := 100; -- selectable >= 0 for dp_fifo_fill + g_block_size : natural := 14; -- to verify g_block_size > or < g_dut_fifo_fill g_dut_use_rd_fill_32b : boolean := false; - g_dut_use_gap : boolean := true; - g_dut_use_random_ctrl : boolean := true + g_dut_use_gap : boolean := false; + g_dut_use_random_ctrl : boolean := false ); end tb_dp_fifo_fill_eop; @@ -75,7 +76,7 @@ architecture tb of tb_dp_fifo_fill_eop is constant c_tx_latency : natural := c_dut_in_latency; -- TX ready latency of TB constant c_tx_void : natural := sel_a_b(c_tx_latency, 1, 0); -- used to avoid empty range VHDL warnings when c_tx_latency=0 constant c_tx_offset_sop : natural := 3; - constant c_tx_period_sop : natural := 14; -- sop in data valid cycle 3, 17, 31, ... + constant c_tx_period_sop : natural := g_block_size; -- sop in data valid cycle 3, 17, 31, ... constant c_tx_offset_eop : natural := sel_a_b(g_dut_use_gap, 12, 16); -- eop in data valid cycle 12, 26, 40, ... constant c_tx_period_eop : natural := c_tx_period_sop; constant c_tx_offset_sync : natural := 3; -- sync in data valid cycle 3, 20, 37, ... @@ -115,6 +116,7 @@ architecture tb of tb_dp_fifo_fill_eop is signal in_val : std_logic; signal in_sop : std_logic; signal in_eop : std_logic; + signal in_en : std_logic := '0'; signal wr_ful : std_logic; signal rd_usedw : std_logic_vector(ceil_log2(largest(g_dut_fifo_size, g_dut_fifo_fill + c_dut_fifo_af_margin + 2)) - 1 downto 0); @@ -148,8 +150,6 @@ architecture tb of tb_dp_fifo_fill_eop is begin - - clk <= not clk or tb_end after clk_period / 2; rst <= '1', '0' after clk_period * 7; @@ -159,7 +159,6 @@ begin -- Input data cnt_val <= in_ready and cnt_en and not gap_en when g_dut_use_random_ctrl else in_ready and not gap_en; - proc_dp_cnt_dat(rst, clk, cnt_val, cnt_dat); proc_dp_tx_data(c_tx_latency, rst, clk, cnt_val, cnt_dat, tx_data, tx_val, in_data, in_val); proc_dp_tx_ctrl(c_tx_offset_sync, c_tx_period_sync, in_data, in_val, in_sync); @@ -169,6 +168,23 @@ begin proc_dp_tx_ctrl(c_tx_offset_gap, c_tx_period_gap, in_data, in_val, gap_en); end generate; + -- Use in_en to ensure that in_sosi starts with in_sop, so no spurious + -- in_eop or in_val without an in_sop. The FIFO will ignore these + -- spurious in_eop or in_val, but for testing the fill_eop mechanism + -- it is more clear to test with only complete input blocks. The + -- general assumption is that only complete blocks are allowed to enter + -- the application code, so incomplete blocks are already avoided at the + -- external interface code of the FPGA and by making sure that FIFOs + -- will stop accepting new blocks before they would overflow. + p_in_en : process + begin + wait until in_sop = '1'; + wait until in_eop = '1'; + wait until in_sop = '1'; + in_en <= '1'; + wait; + end process; + in_bsn <= INCR_UVEC(in_data, c_bsn_offset); in_empty <= INCR_UVEC(in_data, c_empty_offset); in_channel <= INCR_UVEC(in_data, c_channel_offset); @@ -236,10 +252,10 @@ begin in_sosi.bsn(c_dp_bsn_w - 1 downto 0) <= in_bsn(c_dp_bsn_w - 1 downto 0); in_sosi.empty <= in_empty(c_dp_empty_w - 1 downto 0); in_sosi.channel <= in_channel(c_dp_channel_w - 1 downto 0); - in_sosi.sync <= in_sync; - in_sosi.valid <= (in_val and not gap_en); - in_sosi.sop <= in_sop; - in_sosi.eop <= in_eop; + in_sosi.sync <= in_en and in_sync; + in_sosi.valid <= in_en and (in_val and not gap_en); + in_sosi.sop <= in_en and in_sop; + in_sosi.eop <= in_en and in_eop; out_siso.ready <= out_ready; -- SISO out_siso.xon <= '1'; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_packet_merge.vhd b/libraries/base/dp/tb/vhdl/tb_dp_packet_merge.vhd index 61c520974c5017dd9eb8d6a653c1d58ccffbe9b7..2c60d0f34f4d88165c32aac96f975f7629ff2d74 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_packet_merge.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_packet_merge.vhd @@ -66,6 +66,9 @@ entity tb_dp_packet_merge is g_pkt_len : natural := 10; g_pkt_gap : natural := 0; g_align_at_sync : boolean := false; + g_verify_bsn_err : boolean := false; + g_bsn_increment : natural := 2; + g_bsn_err_at_pkt_index : natural := 6; -- force wrong snk_in.bsn for packet with this index, in range(g_nof_repeat) g_use_dp_packet_unmerge : boolean := false ); end tb_dp_packet_merge; @@ -84,13 +87,17 @@ architecture tb of tb_dp_packet_merge is constant c_data_max : unsigned(g_data_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_bsn_error : std_logic_vector(c_dp_stream_bsn_w - 1 downto 0) := (others => '1'); -- use -1 as bsn error value constant c_err_init : natural := 247; + constant c_bsn_err_bi : natural := 31; -- use sufficiently high bsn error bit index, that is outside counter range of c_err_init constant c_channel_init : integer := 5; -- fixed constant c_nof_pkt_not_zero : natural := sel_a_b(g_nof_pkt = 0, 1, g_nof_pkt); constant c_nof_merged_sop : natural := sel_a_b(g_nof_pkt = 0, 0, ceil_div(g_nof_repeat, c_nof_pkt_not_zero)); constant c_verify_at_least : natural := largest(1,c_nof_merged_sop / 2); -- verify that at least some packets have been merged, not exact to allow variation by p_stimuli_mm constant c_verify_data_gap : natural := g_nof_pkt; + constant c_verify_bsn_gap : natural := g_nof_pkt * g_bsn_increment; + constant c_exp_err_at_pkt_index : natural := g_bsn_err_at_pkt_index / sel_a_b(g_nof_pkt = 0, 1, g_nof_pkt); signal tb_end : std_logic := '0'; signal clk : std_logic := '1'; @@ -123,6 +130,8 @@ architecture tb of tb_dp_packet_merge is signal verify_snk_in : t_dp_sosi; signal verify_data : std_logic_vector(g_data_w - 1 downto 0); signal prev_verify_snk_in : t_dp_sosi; + signal merged_pkt_cnt : natural := 0; + signal merged_pkt_err : std_logic; signal verify_hold_sop : std_logic := '0'; signal verify_en_valid : std_logic := '0'; @@ -164,9 +173,10 @@ begin -- Generate data path input data p_stimuli_st : process variable v_sosi : t_dp_sosi := c_dp_sosi_rst; + variable v_bsn : std_logic_vector(c_dp_stream_bsn_w - 1 downto 0); begin -- Adjust initial sosi field values by -1 to compensate for auto increment - v_sosi.bsn := INCR_UVEC(c_bsn_init, -1); + v_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); @@ -178,13 +188,21 @@ begin -- 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_bsn := INCR_UVEC(v_bsn, g_bsn_increment); + v_sosi.bsn := v_bsn; 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_data_w - 1 downto 0)); -- wrap when >= 2**g_data_w v_sosi.err := INCR_UVEC(v_sosi.err, 1); + -- Force bsn error in one snk_in block, to verify src_out.err(g_bsn_err_bi) bit + if g_verify_bsn_err = true then + if I = g_bsn_err_at_pkt_index then + v_sosi.bsn := c_bsn_error; + end if; + end if; + -- Send packet proc_dp_gen_block_data(g_data_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); @@ -235,9 +253,39 @@ begin -- Verify that the output is incrementing data, like the input stimuli proc_dp_verify_data("verify_snk_in.data", c_rl, c_data_max, c_unsigned_1, clk, verify_en_valid, verify_snk_out.ready, verify_snk_in.valid, verify_snk_in.data, prev_verify_snk_in.data); - proc_dp_verify_data("verify_snk_in.bsn", c_rl, c_unsigned_0, to_unsigned(c_verify_data_gap,32), clk, verify_en_sop, verify_snk_out.ready, verify_snk_in.sop, verify_snk_in.bsn, prev_verify_snk_in.bsn); + gen_verify_bsn_increment : if g_verify_bsn_err = false generate + proc_dp_verify_data("verify_snk_in.bsn", c_rl, c_unsigned_0, to_unsigned(c_verify_bsn_gap, 32), clk, verify_en_sop, verify_snk_out.ready, verify_snk_in.sop, verify_snk_in.bsn, prev_verify_snk_in.bsn); + gen_verify_err : if g_nof_pkt = 1 generate + -- Assume verifying g_nof_pkt = 1 is sufficient. Verifing g_nof_pkt > 1 is more difficult, + -- because the merged output error field is the bitwise OR of the input error fields + proc_dp_verify_data("verify_snk_in.err", c_rl, c_unsigned_0, to_unsigned(c_verify_data_gap,32), clk, verify_en_eop, verify_snk_out.ready, verify_snk_in.eop, verify_snk_in.err, prev_verify_snk_in.err); + end generate; + end generate; proc_dp_verify_data("verify_snk_in.channel", c_rl, c_unsigned_0, to_unsigned(c_verify_data_gap,32), clk, verify_en_sop, verify_snk_out.ready, verify_snk_in.sop, verify_snk_in.channel, prev_verify_snk_in.channel); + -- Verify that the output bsn error bit is set if an input block was missed in a merge + merged_pkt_err <= verify_snk_in.err(c_bsn_err_bi); + + gen_verify_bsn_err : if g_verify_bsn_err = true generate + p_verify_bsn_err : process(clk) + begin + if rising_edge(clk) then + -- count number of merged packets + if verify_snk_in.sop = '1' then + merged_pkt_cnt <= merged_pkt_cnt + 1; + end if; + -- verify err field for merged packet with input bsn error + if verify_snk_in.sop = '1' then + if merged_pkt_cnt = c_exp_err_at_pkt_index + 1 and g_bsn_increment > 0 then + assert merged_pkt_err = '1' report "Unexpected sosi.err = 0" severity ERROR; + else + assert merged_pkt_err = '0' report "Unexpected sosi.err = 1" severity ERROR; + end if; + end if; + end if; + end process; + end generate; + -- Verify output packet ctrl proc_dp_verify_sop_and_eop(clk, verify_snk_in.valid, verify_snk_in.sop, verify_snk_in.eop, verify_hold_sop); @@ -256,7 +304,9 @@ begin u_dp_packet_merge : entity work.dp_packet_merge generic map ( g_nof_pkt => g_nof_pkt, - g_align_at_sync => g_align_at_sync + g_align_at_sync => g_align_at_sync, + g_bsn_increment => g_bsn_increment, + g_bsn_err_bi => c_bsn_err_bi ) port map ( rst => rst, diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_fifo_fill_eop.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_fifo_fill_eop.vhd index e3c449afb2aa9b37f22e9b0ddf71c866d0ffa1ac..60fe18d02750d66821a9ea577a1cef2dcf705ffe 100644 --- a/libraries/base/dp/tb/vhdl/tb_tb_dp_fifo_fill_eop.vhd +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_fifo_fill_eop.vhd @@ -45,7 +45,19 @@ end tb_tb_dp_fifo_fill_eop; architecture tb of tb_tb_dp_fifo_fill_eop is signal tb_end : std_logic := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' begin - -- Try FIFO settings : GENERIC MAP (g_dut_use_dual_clock, g_dut_use_bsn, g_dut_use_empty, g_dut_use_channel, g_dut_use_sync, g_dut_fifo_rl, g_dut_fifo_size, g_dut_fifo_fill, g_dut_use_rd_fill_32b, g_dut_use_gap, g_dut_use_random_ctrl) + -- Try FIFO settings + -- g_dut_use_dual_clock : boolean := true; + -- g_dut_use_bsn : boolean := false; + -- g_dut_use_empty : boolean := false; + -- g_dut_use_channel : boolean := false; + -- g_dut_use_sync : boolean := false; + -- g_dut_fifo_rl : natural := 1; -- internal RL, use 0 for look ahead FIFO, default 1 for normal FIFO + -- g_dut_fifo_size : natural := 128; + -- g_dut_fifo_fill : natural := 100; -- selectable >= 0 for dp_fifo_fill + -- g_block_size : natural := 14; + -- g_dut_use_rd_fill_32b : boolean := false; + -- g_dut_use_gap : boolean := true; + -- g_dut_use_random_ctrl : boolean := true u_dut_sc_1 : entity work.tb_dp_fifo_fill_eop generic map (g_dut_use_dual_clock => false, g_dut_fifo_rl => 1, g_dut_use_random_ctrl => false); u_dut_sc_1_no_gap : entity work.tb_dp_fifo_fill_eop generic map (g_dut_use_dual_clock => false, g_dut_fifo_rl => 1, g_dut_use_random_ctrl => false, g_dut_use_gap => false); @@ -59,4 +71,8 @@ begin u_dut_dc_1_rand_no_gap : entity work.tb_dp_fifo_fill_eop generic map (g_dut_use_dual_clock => true, g_dut_fifo_rl => 1, g_dut_use_random_ctrl => true, g_dut_use_gap => false); u_dut_sc_0_rand_no_gap : entity work.tb_dp_fifo_fill_eop generic map (g_dut_use_dual_clock => false, g_dut_fifo_rl => 0, g_dut_use_random_ctrl => true, g_dut_use_gap => false); u_dut_dc_0_rand_no_gap : entity work.tb_dp_fifo_fill_eop generic map (g_dut_use_dual_clock => true, g_dut_fifo_rl => 0, g_dut_use_random_ctrl => true, g_dut_use_gap => false); + + u_dut_sc_1_blk_gt_fill : entity work.tb_dp_fifo_fill_eop generic map (g_dut_use_dual_clock => false, g_dut_fifo_rl => 1, g_dut_use_random_ctrl => false, g_dut_use_gap => false, + g_dut_fifo_fill => 10, g_block_size => 20); + end tb; diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge.vhd index db1e7726c2d5e800beec5d17c4889c7705f72776..e62fe8c16a891094fb94ad976a6b7b9ad54ba95e 100644 --- a/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge.vhd +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge.vhd @@ -45,30 +45,39 @@ begin -- g_flow_control_stimuli : t_dp_flow_control_enum := e_active; -- always active, random or pulse flow control -- g_flow_control_verify : t_dp_flow_control_enum := e_active; -- always active, random or pulse flow control -- -- specific - -- g_data_w : NATURAL := 4; - -- g_nof_repeat : NATURAL := 20; - -- g_nof_pkt : NATURAL := 3; - -- g_pkt_len : NATURAL := 29; - -- g_pkt_gap : NATURAL := 0; - -- g_align_at_sync : BOOLEAN := FALSE; - -- g_use_dp_packet_unmerge : BOOLEAN := FALSE + -- g_data_w : natural := 4; + -- g_nof_repeat : natural := 20; + -- g_nof_pkt : natural := 3; + -- g_pkt_len : natural := 29; + -- g_pkt_gap : natural := 0; + -- g_align_at_sync : boolean := false; + -- g_verify_bsn_err : boolean := false; + -- g_bsn_increment : natural := 0; + -- g_bsn_err_at_pkt_index : natural := 3; + -- g_use_dp_packet_unmerge : boolean := false - u_act_act_8_nof_0 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 0, 29, 0, false, false); - u_act_act_8_nof_1 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 1, 29, 0, false, false); - u_act_act_8_nof_2 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 2, 29, 0, false, false); - u_act_act_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, false); - u_act_act_8_nof_4 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 4, 29, 0, false, false); - u_act_act_8_nof_5 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 5, 29, 0, false, false); - u_act_act_8_nof_6 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 6, 29, 0, false, false); - u_act_act_8_nof_7 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 7, 29, 0, false, false); + u_act_act_8_nof_0 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 0, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_1 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 1, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_2 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 2, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_4 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 4, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_5 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 5, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_6 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 6, 29, 0, false, false, 1, 0, false); + u_act_act_8_nof_7 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 7, 29, 0, false, false, 1, 0, false); - u_rnd_act_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_random, e_active, 8, c_nof_repeat, 3, 29, 0, false, false); - u_rnd_rnd_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_random, e_random, 8, c_nof_repeat, 3, 29, 0, false, false); - u_pls_act_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_pulse, e_active, 8, c_nof_repeat, 3, 29, 0, false, false); - u_pls_rnd_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_pulse, e_random, 8, c_nof_repeat, 3, 29, 0, false, false); - u_pls_pls_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_pulse, e_pulse, 8, c_nof_repeat, 3, 29, 0, false, false); + u_rnd_act_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_random, e_active, 8, c_nof_repeat, 3, 29, 0, false, false, 2, 0, false); + u_rnd_rnd_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_random, e_random, 8, c_nof_repeat, 3, 29, 0, false, false, 3, 0, false); + u_pls_act_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_pulse, e_active, 8, c_nof_repeat, 3, 29, 0, false, false, 4, 0, false); + u_pls_rnd_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_pulse, e_random, 8, c_nof_repeat, 3, 29, 0, false, false, 5, 0, false); + u_pls_pls_8_nof_3 : entity work.tb_dp_packet_merge generic map ( e_pulse, e_pulse, 8, c_nof_repeat, 3, 29, 0, false, false, 6, 0, false); - u_rnd_act_8_nof_1 : entity work.tb_dp_packet_merge generic map ( e_random, e_active, 8, c_nof_repeat, 1, 29, 0, false, false); - u_rnd_act_8_nof_3_gap : entity work.tb_dp_packet_merge generic map ( e_random, e_active, 8, c_nof_repeat, 3, 29, 17, false, false); + u_rnd_act_8_nof_1 : entity work.tb_dp_packet_merge generic map ( e_random, e_active, 8, c_nof_repeat, 1, 29, 0, false, false, 1, 0, false); + u_rnd_act_8_nof_3_gap : entity work.tb_dp_packet_merge generic map ( e_random, e_active, 8, c_nof_repeat, 3, 29, 17, false, false, 1, 0, false); + + u_act_act_8_nof_3_no_err : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, true, 0, 10, false); + u_act_act_8_nof_3_err_10 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, true, 1, 10, false); + u_act_act_8_nof_3_err_11 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, true, 1, 11, false); + u_act_act_8_nof_3_err_12 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, true, 1, 12, false); + u_act_act_8_nof_3_err_13 : entity work.tb_dp_packet_merge generic map ( e_active, e_active, 8, c_nof_repeat, 3, 29, 0, false, true, 1, 13, false); end tb; diff --git a/libraries/base/ring/src/vhdl/ring_lane.vhd b/libraries/base/ring/src/vhdl/ring_lane.vhd index 27ac241d28a492ad505d8a3900bf25bcbec00f0c..374faeb6d6c02848496fae5dac13f8e24548e6b9 100644 --- a/libraries/base/ring/src/vhdl/ring_lane.vhd +++ b/libraries/base/ring/src/vhdl/ring_lane.vhd @@ -21,16 +21,11 @@ ------------------------------------------------------------------------------- -- -- Author: R. van der Walle - +-- -- Purpose: Implement the function of a complete ring lane by combining ring_lane/tx. --- Description: See https://support.astron.nl/confluence/x/jyu7Ag +-- Description: +-- . See "L5 SDPFW Design Document: Ring" at https://support.astron.nl/confluence/x/jyu7Ag -- Remark: --- . Note that the dp_fifo_fill_eop in dp_block_validate_err cannot handle --- continues stream of blocks without a gap between blocks the dp_fifo_fill_eop --- needs 1 cycle to process a block. Streaming without gaps may cause the fifo --- to overflow. Bursts of blocks can be handled by increasing gvalidate_err_fifo_size. - -------------------------------------------------------------------------------- library IEEE, common_lib, mm_lib, dp_lib; use IEEE.std_logic_1164.all;