diff --git a/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd b/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd index 74e3db58e912b6c3b7812450f7840361c155f2ea..0cac366741975ded016d03c75dc5f0ddd727f928 100644 --- a/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd +++ b/libraries/base/dp/src/vhdl/dp_block_validate_err.vhd @@ -120,13 +120,22 @@ ARCHITECTURE rtl OF dp_block_validate_err IS -- Registers in st_clk domain SIGNAL count_reg : STD_LOGIC_VECTOR(c_mm_reg.nof_dat*c_mm_reg.dat_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL nxt_cnt_en : STD_LOGIC; + SIGNAL cnt_en : STD_LOGIC := '0'; + SIGNAL cnt_this_eop : STD_LOGIC; + SIGNAL mm_cnt_clr : STD_LOGIC; SIGNAL cnt_clr : STD_LOGIC; SIGNAL cnt_blk : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); + SIGNAL cnt_blk_en : STD_LOGIC; SIGNAL cnt_discarded : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); SIGNAL cnt_discarded_en : STD_LOGIC; - SIGNAL cnt_err : t_cnt_err_arr(g_nof_err_counts-1 DOWNTO 0); - SIGNAL cnt_err_en : STD_LOGIC_VECTOR(g_nof_err_counts-1 DOWNTO 0); + SIGNAL cnt_err_arr : t_cnt_err_arr(g_nof_err_counts-1 DOWNTO 0); + SIGNAL cnt_err_en_arr : STD_LOGIC_VECTOR(g_nof_err_counts-1 DOWNTO 0); + + SIGNAL hold_cnt_blk : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); + SIGNAL hold_cnt_discarded : STD_LOGIC_VECTOR(g_cnt_w-1 DOWNTO 0); + SIGNAL hold_cnt_err_arr : t_cnt_err_arr(g_nof_err_counts-1 DOWNTO 0); SIGNAL err_ok : STD_LOGIC; SIGNAL err_ok_reg : STD_LOGIC; @@ -152,7 +161,15 @@ BEGIN out_pulse => cnt_clr ); + -- . clear block counters immediately at cnt_clr + -- . start block counters after sync, e.g. to align block counters in different nodes in + -- case the snk_in was (already) active during the cnt_clr + nxt_cnt_en <= '0' WHEN cnt_clr = '1' ELSE '1' WHEN snk_in.sync = '1' ELSE cnt_en; + cnt_en <= nxt_cnt_en WHEN rising_edge(dp_clk); + cnt_this_eop <= cnt_en AND snk_in.eop; + -- block counter + cnt_blk_en <= cnt_this_eop; u_blk_counter : ENTITY common_lib.common_counter GENERIC MAP ( g_width => g_cnt_w, @@ -163,12 +180,12 @@ BEGIN clk => dp_clk, cnt_clr => cnt_clr, - cnt_en => snk_in.eop, + cnt_en => cnt_blk_en, count => cnt_blk ); -- discarded block counter - cnt_discarded_en <= snk_in.eop WHEN TO_UINT(snk_in.err(g_nof_err_counts-1 DOWNTO 0)) > 0 ELSE '0'; + cnt_discarded_en <= cnt_this_eop WHEN TO_UINT(snk_in.err(g_nof_err_counts-1 DOWNTO 0)) > 0 ELSE '0'; u_discarded_counter : ENTITY common_lib.common_counter GENERIC MAP ( g_width => g_cnt_w, @@ -185,7 +202,7 @@ BEGIN -- error counters gen_err_counters : FOR I IN 0 TO g_nof_err_counts-1 GENERATE - cnt_err_en(I) <= snk_in.eop AND snk_in.err(I); + cnt_err_en_arr(I) <= cnt_this_eop AND snk_in.err(I); u_blk_counter : ENTITY common_lib.common_counter GENERIC MAP ( g_width => g_cnt_w, @@ -196,17 +213,33 @@ BEGIN clk => dp_clk, cnt_clr => cnt_clr, - cnt_en => cnt_err_en(I), - count => cnt_err(I) + cnt_en => cnt_err_en_arr(I), + count => cnt_err_arr(I) ); END GENERATE; + -- Hold counter values at snk_in.sync to have stable values for MM read for comparision between nodes + p_hold_counters : PROCESS(dp_clk) + BEGIN + IF rising_edge(dp_clk) THEN + IF cnt_clr = '1' THEN + hold_cnt_blk <= (OTHERS=>'0'); + hold_cnt_discarded <= (OTHERS=>'0'); + hold_cnt_err_arr <= (OTHERS=>(OTHERS=>'0')); + ELSIF snk_in.sync = '1' THEN + hold_cnt_blk <= cnt_blk; + hold_cnt_discarded <= cnt_discarded; + hold_cnt_err_arr <= cnt_err_arr; + END IF; + END IF; + END PROCESS; + -- Register mapping gen_reg : FOR I IN 0 TO g_nof_err_counts-1 GENERATE - count_reg((I + 1) * c_word_w - 1 DOWNTO I * c_word_w) <= RESIZE_UVEC(cnt_err(I), c_word_w); + count_reg((I + 1) * c_word_w - 1 DOWNTO I * c_word_w) <= RESIZE_UVEC(hold_cnt_err_arr(I), c_word_w); END GENERATE; - count_reg((g_nof_err_counts+1) * c_word_w - 1 DOWNTO g_nof_err_counts * c_word_w ) <= RESIZE_UVEC(cnt_discarded, c_word_w); - count_reg((g_nof_err_counts+2) * c_word_w - 1 DOWNTO (g_nof_err_counts+1) * c_word_w ) <= RESIZE_UVEC(cnt_blk, c_word_w); + count_reg((g_nof_err_counts+1) * c_word_w - 1 DOWNTO g_nof_err_counts * c_word_w ) <= RESIZE_UVEC(hold_cnt_discarded, c_word_w); + count_reg((g_nof_err_counts+2) * c_word_w - 1 DOWNTO (g_nof_err_counts+1) * c_word_w ) <= RESIZE_UVEC(hold_cnt_blk, c_word_w); u_reg : ENTITY common_lib.common_reg_r_w_dc GENERIC MAP ( diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd index 9b0c20e901e1475494ae2798e9c98d159599e05e..4061a3570a51111739096ac038791ac7987bcb29 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_block_validate_err.vhd @@ -49,7 +49,7 @@ ENTITY tb_dp_block_validate_err IS g_max_block_size : NATURAL := 9; g_nof_err_counts : NATURAL := 8; g_gap_size : NATURAL := 4; - g_cnt_w : NATURAL := 3 + g_cnt_w : NATURAL := 3 ); END tb_dp_block_validate_err; @@ -64,10 +64,11 @@ ARCHITECTURE tb OF tb_dp_block_validate_err IS CONSTANT c_dut_pipeline : NATURAL := g_nof_data_per_blk + 3; CONSTANT c_nof_sync : NATURAL := 5; - CONSTANT c_nof_blk : NATURAL := g_nof_blocks_per_sync * c_nof_sync; + CONSTANT c_nof_blk : NATURAL := g_nof_blocks_per_sync * (c_nof_sync - 1); CONSTANT c_nof_discarded : NATURAL := c_nof_blk - ceil_div(c_nof_blk, 2**g_nof_err_counts); CONSTANT c_max_cnt : NATURAL := 2**g_cnt_w -1; + CONSTANT c_mm_addr_dp_clear : NATURAL := g_nof_err_counts+2; CONSTANT c_mm_addr_dp_blk_cnt : NATURAL := g_nof_err_counts+1; CONSTANT c_mm_addr_dp_discarded_cnt : NATURAL := g_nof_err_counts; CONSTANT c_exp_blk_cnt : NATURAL := sel_a_b(c_nof_blk < c_max_cnt, c_nof_blk, c_max_cnt); @@ -78,6 +79,7 @@ ARCHITECTURE tb OF tb_dp_block_validate_err IS SIGNAL rst : STD_LOGIC := '1'; SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL stimuli_rst : STD_LOGIC := '1'; SIGNAL stimuli_end : STD_LOGIC; SIGNAL stimuli_sosi : t_dp_sosi; SIGNAL stimuli_siso : t_dp_siso; @@ -91,6 +93,11 @@ ARCHITECTURE tb OF tb_dp_block_validate_err IS SIGNAL reference_siso : t_dp_siso := c_dp_siso_rdy; SIGNAL reg_mosi : t_mem_mosi := c_mem_mosi_rst; SIGNAL reg_miso : t_mem_miso := c_mem_miso_rst; + + SIGNAL rd_blk_cnt : NATURAL; + SIGNAL rd_discarded_cnt : NATURAL; + SIGNAL rd_err_cnt_arr : t_natural_arr(g_nof_err_counts-1 DOWNTO 0); + BEGIN ------------------------------------------------------------------------------ @@ -99,11 +106,13 @@ BEGIN dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2; mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; rst <= '1', '0' AFTER c_dp_clk_period*7; - + ------------------------------------------------------------------------------ -- Stimuli: ------------------------------------------------------------------------------ + stimuli_rst <= '1', '0' AFTER c_dp_clk_period*17; + -- Generate snk_in with data frames u_stimuli : ENTITY work.dp_stream_stimuli GENERIC MAP ( @@ -115,7 +124,7 @@ BEGIN g_err_incr => 1 ) PORT MAP ( - rst => rst, + rst => stimuli_rst, clk => dp_clk, -- Generate stimuli @@ -212,14 +221,19 @@ BEGIN -- this can be calculated as the dp error field is a counter up to c_nof_blk - 1. VARIABLE v_N : INTEGER := 0; BEGIN + proc_common_wait_until_low(mm_clk, rst); + proc_mem_mm_bus_wr(c_mm_addr_dp_clear, 1, mm_clk, reg_mosi); + proc_common_wait_until_lo_hi(dp_clk, stimuli_end); proc_common_wait_some_cycles(dp_clk, c_dut_pipeline + 1); - proc_common_wait_until_lo_hi(mm_clk, mm_clk); + proc_common_wait_some_cycles(mm_clk, 1); proc_mem_mm_bus_rd(c_mm_addr_dp_discarded_cnt, mm_clk, reg_miso, reg_mosi); proc_mem_mm_bus_rd_latency(1, mm_clk); + rd_discarded_cnt <= TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)); ASSERT c_exp_discarded_cnt = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong total discarded block count" SEVERITY ERROR; proc_mem_mm_bus_rd(c_mm_addr_dp_blk_cnt, mm_clk, reg_miso, reg_mosi); proc_mem_mm_bus_rd_latency(1, mm_clk); + rd_blk_cnt <= TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)); ASSERT c_exp_blk_cnt = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong total block count" SEVERITY ERROR; FOR I IN 0 TO g_nof_err_counts-1 LOOP v_X := 2**I * ((c_nof_blk-1) / 2**(I+1)); @@ -236,13 +250,25 @@ BEGIN proc_mem_mm_bus_rd(I, mm_clk, reg_miso, reg_mosi); proc_mem_mm_bus_rd_latency(1, mm_clk); + rd_err_cnt_arr(I) <= TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)); ASSERT v_N = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong error count" SEVERITY ERROR; END LOOP; proc_common_wait_some_cycles(dp_clk, 10); + + -- check cnt clear + proc_mem_mm_bus_wr(c_mm_addr_dp_clear, 1, mm_clk, reg_mosi); + proc_common_wait_cross_clock_domain_latency(mm_clk, dp_clk); + + proc_mem_mm_bus_rd(c_mm_addr_dp_discarded_cnt, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + ASSERT 0 = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong cleared total discarded block count" SEVERITY ERROR; + proc_mem_mm_bus_rd(c_mm_addr_dp_blk_cnt, mm_clk, reg_miso, reg_mosi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + ASSERT 0 = TO_UINT(reg_miso.rddata(c_word_w-1 DOWNTO 0)) REPORT "Wrong cleared total block count" SEVERITY ERROR; + proc_common_wait_some_cycles(dp_clk, 10); + tb_end <= '1'; WAIT; END PROCESS; - tb_end <= '0', stimuli_end AFTER (1 + 10*c_dut_pipeline)*c_dp_clk_period; - END tb;