From 1b3e141a4bd37703b73e8f2b7f213c5232ecb4f5 Mon Sep 17 00:00:00 2001 From: Eric Kooistra <kooistra@astron.nl> Date: Tue, 8 Aug 2023 12:56:14 +0200 Subject: [PATCH] Report out of order input BSN via src_out.err bit. --- .../base/dp/src/vhdl/dp_packet_merge.vhd | 40 ++++++++++--- .../base/dp/tb/vhdl/tb_dp_packet_merge.vhd | 58 +++++++++++++++++-- .../base/dp/tb/vhdl/tb_tb_dp_packet_merge.vhd | 53 ++++++++++------- 3 files changed, 117 insertions(+), 34 deletions(-) diff --git a/libraries/base/dp/src/vhdl/dp_packet_merge.vhd b/libraries/base/dp/src/vhdl/dp_packet_merge.vhd index 5e4b1d58d9..551460047f 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_packet_merge.vhd b/libraries/base/dp/tb/vhdl/tb_dp_packet_merge.vhd index 61c520974c..2c60d0f34f 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_packet_merge.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_packet_merge.vhd index db1e7726c2..e62fe8c16a 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; -- GitLab