diff --git a/libraries/base/dp/tb/vhdl/tb_dp_bsn_sync_scheduler.vhd b/libraries/base/dp/tb/vhdl/tb_dp_bsn_sync_scheduler.vhd index d8d240da3aa97854192aa452520d4153d1b4301f..1fc9befefb64f95e626b59894d0a2e94830d2eef 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_bsn_sync_scheduler.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_sync_scheduler.vhd @@ -33,7 +33,7 @@ -- ctrl_interval_size = g_nof_samples_per_output_sync -- * output sync interval recovery in case of lost input blocks -- Usage: --- > as 8 +-- > as 4 -- > run -all -- View in Wave window u_dut: r, nxt_r, and tb: in_sosi, out_sosi, -- out_sync, out_start @@ -62,7 +62,7 @@ -- because the sync part is already verified by -- tb_tb_dp_bsn_sync_scheduler.vhd. -- 5a For all ASSERTs, verify that the ERROR or FAILURE can occur by e.g. --- temporarily changing the condition +-- temporarily changing the ASSERT condition -- b Initialy used LOOP in p_stimuli to repeat test. Later used list of -- c_nof_test_intervals and tb_state to try different stimuli. @@ -108,6 +108,7 @@ ARCHITECTURE tb OF tb_dp_bsn_sync_scheduler IS CONSTANT c_sim_nof_blocks : NATURAL := c_nof_block_per_test_interval * c_nof_test_intervals; CONSTANT c_output_nof_blocks_min : NATURAL := g_nof_samples_per_output_sync / g_block_size; + CONSTANT c_enable_init_nof_bsn : NATURAL := ceil_value(c_output_nof_blocks_min / g_block_size + 10, g_nof_block_per_input_sync); SIGNAL clk : STD_LOGIC := '1'; SIGNAL rst : STD_LOGIC := '1'; @@ -153,18 +154,20 @@ ARCHITECTURE tb OF tb_dp_bsn_sync_scheduler IS SIGNAL in_sosi_integer : t_dp_sosi_integer; SIGNAL out_sosi_integer : t_dp_sosi_integer; - SIGNAL verify_sosi_equal : STD_LOGIC := '0'; - SIGNAL verify_sync : STD_LOGIC := '1'; - SIGNAL verify_mon_output_sync_bsn : STD_LOGIC := '1'; + SIGNAL verify_sosi_equal : STD_LOGIC := '0'; + SIGNAL verify_sync : STD_LOGIC := '1'; + SIGNAL recover_from_in_lost : STD_LOGIC := '0'; + + SIGNAL verifying_sync_equal : STD_LOGIC := '0'; SIGNAL prev_out_enable : STD_LOGIC := '0'; - SIGNAL out_eop_dly : STD_LOGIC := '0'; SIGNAL pending_out_enable : STD_LOGIC := '0'; SIGNAL pending_out_disable : STD_LOGIC := '0'; SIGNAL expected_out_enable : STD_LOGIC := '0'; SIGNAL expecting_out_start : STD_LOGIC := '0'; - - SIGNAL verifying_sync_equal : STD_LOGIC := '0'; + SIGNAL hold_out_eop : STD_LOGIC := '0'; + SIGNAL hold_out_sop : STD_LOGIC := '0'; + SIGNAL out_sop_cnt : NATURAL := 0; SIGNAL dbg_out_sosi_sync : STD_LOGIC; SIGNAL dbg_out_sosi_sop : STD_LOGIC; @@ -176,14 +179,16 @@ ARCHITECTURE tb OF tb_dp_bsn_sync_scheduler IS -- Local procedures PROCEDURE proc_output_enable(SIGNAL clk : IN STD_LOGIC; SIGNAL cnt : IN INTEGER; + SIGNAL sync : IN STD_LOGIC; SIGNAL mon_input_bsn_at_sync : IN STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); SIGNAL stimuli_state : OUT t_stimuli_state_enum; SIGNAL ctrl_start_bsn : OUT STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0); SIGNAL ctrl_enable : OUT STD_LOGIC; SIGNAL ctrl_enable_evt : OUT STD_LOGIC) IS BEGIN + proc_common_wait_until_hi_lo(clk, sync); -- (re)enable at begin of sync interval stimuli_state <= e_en; - ctrl_start_bsn <= ADD_UVEC(mon_input_bsn_at_sync, TO_UVEC(g_nof_block_per_input_sync, c_natural_w)); -- determine BSN in the future + ctrl_start_bsn <= ADD_UVEC(mon_input_bsn_at_sync, TO_UVEC(c_enable_init_nof_bsn, c_natural_w)); -- determine BSN in the future ctrl_enable <= '1'; ctrl_enable_evt <= '1'; proc_common_wait_some_cycles(clk, 1); @@ -198,15 +203,19 @@ ARCHITECTURE tb OF tb_dp_bsn_sync_scheduler IS SIGNAL ctrl_enable : OUT STD_LOGIC; SIGNAL ctrl_enable_evt : OUT STD_LOGIC) IS BEGIN - proc_output_enable(clk, cnt, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); + proc_output_enable(clk, cnt, in_sync, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); stimuli_state <= e_re; END proc_output_re_enable; PROCEDURE proc_output_disable(SIGNAL stimuli_state : OUT t_stimuli_state_enum; - SIGNAL ctrl_enable : OUT STD_LOGIC) IS + SIGNAL ctrl_enable : OUT STD_LOGIC; + SIGNAL ctrl_enable_evt : OUT STD_LOGIC) IS BEGIN stimuli_state <= e_dis; ctrl_enable <= '0'; + ctrl_enable_evt <= '1'; + proc_common_wait_some_cycles(clk, 1); + ctrl_enable_evt <= '0'; END proc_output_disable; BEGIN @@ -234,11 +243,11 @@ BEGIN proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_begin_of_test_interval, clk, cnt); -- Start of test_interval: Enable output - proc_output_enable(clk, cnt, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); + proc_output_enable(clk, cnt, in_sync, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); -- End of test_interval: Disable output proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_end_of_test_interval, clk, cnt); - proc_output_disable(stimuli_state, ctrl_enable); + proc_output_disable(stimuli_state, ctrl_enable, ctrl_enable_evt); ------------------------------------------------------------------------------ -- Re enable output when already enabled @@ -247,7 +256,7 @@ BEGIN -- Start of test_interval: Enable output proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_begin_of_test_interval, clk, cnt); - proc_output_enable(clk, cnt, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); + proc_output_enable(clk, cnt, in_sync, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); -- Mid of test_interval: Re-enable output proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_mid_of_test_interval, clk, cnt); @@ -255,7 +264,7 @@ BEGIN -- End of test_interval: Disable output proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_end_of_test_interval, clk, cnt); - proc_output_disable(stimuli_state, ctrl_enable); + proc_output_disable(stimuli_state, ctrl_enable, ctrl_enable_evt); ------------------------------------------------------------------------------ -- Lost input blocks @@ -264,13 +273,14 @@ BEGIN -- Start of test_interval: Enable output proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_begin_of_test_interval, clk, cnt); - proc_output_enable(clk, cnt, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); + proc_output_enable(clk, cnt, in_sync, mon_input_bsn_at_sync, stimuli_state, ctrl_start_bsn, ctrl_enable, ctrl_enable_evt); -- Early in test_interval: Disable input to simulate lost blocks proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_early_in_test_interval, clk, cnt); stimuli_state <= e_lost; proc_common_wait_until_high(clk, stimuli_sosi.eop); in_lost <= '1'; -- high after eop, so high at next sop + recover_from_in_lost <= '1'; FOR I IN 0 TO c_nof_lost_input_blocks-1 LOOP proc_common_wait_some_cycles(clk, 1); proc_common_wait_until_high(clk, stimuli_sosi.eop); @@ -278,15 +288,14 @@ BEGIN in_lost <= '0'; -- low after eop, so low at next sop stimuli_state <= e_en; -- Wait for some cycles that DUT needs to catch up after lost input (see nxt_r.update_bsn in DUT) - verify_mon_output_sync_bsn <= '0'; - FOR I IN 0 TO c_nof_lost_input_blocks / c_output_nof_blocks_min + 2 LOOP -- + for some extra margin + FOR I IN 0 TO c_nof_lost_input_blocks / c_output_nof_blocks_min + 5 LOOP -- + for some extra margin proc_common_wait_some_cycles(clk, 1); END LOOP; - verify_mon_output_sync_bsn <= '1'; + recover_from_in_lost <= '0'; -- End of test_interval: Disable output proc_common_wait_until_value(test_interval * c_nof_clk_per_test_interval + c_end_of_test_interval, clk, cnt); - proc_output_disable(stimuli_state, ctrl_enable); + proc_output_disable(stimuli_state, ctrl_enable, ctrl_enable_evt); WAIT; END PROCESS; @@ -338,46 +347,67 @@ BEGIN ----------------------------------------------------------------------------- -- . Verify out_enable ----------------------------------------------------------------------------- - out_eop_dly <= out_sosi.eop WHEN rising_edge(clk); + p_hold_out_eop : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + IF out_sosi.eop = '1' THEN + hold_out_eop <= '1'; + ELSIF out_sosi.sop = '1' THEN + hold_out_eop <= '0'; + END IF; + END IF; + END PROCESS; - p_expected_out_enable : PROCESS(ctrl_enable, ctrl_enable_evt, in_sosi, ctrl_start_bsn, pending_out_enable, pending_out_disable, out_eop_dly) + p_expected_out_enable : PROCESS(ctrl_enable, ctrl_enable_evt, in_sosi, ctrl_start_bsn, out_enable, pending_out_enable, pending_out_disable, hold_out_eop) BEGIN -- Determine expected out_enable IF ctrl_enable = '1' THEN - -- Detect output enable event and determine whether it is scheduled in the future + -- Detect output enable event IF ctrl_enable_evt = '1' THEN + -- Determine whether the output enable event is scheduled in the future IF UNSIGNED(in_sosi.bsn) < UNSIGNED(ctrl_start_bsn) THEN pending_out_enable <= '1'; - END IF; + + -- Detect output re-enable event, to plan output disable before re-enable + IF out_enable = '1' THEN + IF hold_out_eop = '1' THEN + expected_out_enable <= '0'; + ELSE + pending_out_disable <= '1'; + END IF; + END IF; + END IF; -- else ignore output enable event in the past END IF; - -- Expected out_enable enabled + -- Enable expected_out_enable at start BSN (and at in_sosi.sop) IF pending_out_enable = '1' THEN IF UNSIGNED(in_sosi.bsn) >= UNSIGNED(ctrl_start_bsn) THEN expected_out_enable <= '1'; pending_out_enable <= '0'; END IF; END IF; - - -- Remove any pending output disable - pending_out_disable <= '0'; ELSE - -- Remove any pending output enable + -- Immediately remove any pending output enable pending_out_enable <= '0'; - -- Detect output disable event + -- Detect output disable event, to plan output disable IF ctrl_enable_evt = '1' THEN - pending_out_disable <= '1'; + IF hold_out_eop = '1' THEN + expected_out_enable <= '0'; + ELSE + pending_out_disable <= '1'; + END IF; END IF; + END IF; - -- Expected out_enable disabled - IF pending_out_disable <= '1' AND out_eop_dly = '1' THEN - expected_out_enable <= '0'; - pending_out_disable <= '0'; - END IF; + -- Expected out_enable disabled between block boundaries + IF pending_out_disable = '1' AND hold_out_eop = '1' THEN + expected_out_enable <= '0'; + pending_out_disable <= '0'; END IF; END PROCESS; + p_verify_out_enable : PROCESS(clk) BEGIN -- Use registered values to compare, to avoid combinatorial differences @@ -396,7 +426,20 @@ BEGIN END PROCESS; ----------------------------------------------------------------------------- - -- . Verify out_enable + -- . Verify that there was valid output + ----------------------------------------------------------------------------- + + out_sop_cnt <= out_sop_cnt + 1 WHEN rising_edge(clk) AND out_sosi.sop = '1'; + + p_verify_output : PROCESS + BEGIN + WAIT UNTIL tb_end = '1'; + ASSERT out_sop_cnt > 0 REPORT "There was no output." SEVERITY ERROR; + WAIT; + END PROCESS; + + ----------------------------------------------------------------------------- + -- . Verify out_start ----------------------------------------------------------------------------- p_expecting_out_start : PROCESS(clk) @@ -427,11 +470,9 @@ BEGIN REPORT "Unexpected out_start" SEVERITY ERROR; END IF; - -- Check when out_enable goes low whether out_start was missed - IF out_enable = '0' AND prev_out_enable = '1' THEN - IF expecting_out_start = '1' THEN - REPORT "Missed out_start" SEVERITY ERROR; - END IF; + -- Check when out_enable goes high whether out_start is missed + IF out_start = '0' AND out_enable = '1' AND prev_out_enable = '0' THEN + REPORT "Missed out_start" SEVERITY ERROR; END IF; END IF; END PROCESS; @@ -454,6 +495,9 @@ BEGIN proc_dp_verify_sosi_equal("valid", clk, verify_sosi_equal, out_sosi_integer, in_sosi_integer); proc_dp_verify_sosi_equal( "data", clk, verify_sosi_equal, out_sosi_integer, in_sosi_integer); + -- Verify that out_sosi blocks have sop and eop + proc_dp_verify_sop_and_eop(clk, out_sosi.valid, out_sosi.sop, out_sosi.eop, hold_out_sop); + ----------------------------------------------------------------------------- -- . Verify out_sosi.sync = in_sosi.sync, when sync interval is not changed ----------------------------------------------------------------------------- @@ -465,11 +509,26 @@ BEGIN ----------------------------------------------------------------------------- -- . Verify out_sosi.sync interval ----------------------------------------------------------------------------- + p_verify_sync : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + IF ctrl_enable = '1' AND ctrl_enable_evt = '1' THEN + verify_sync <= '0'; -- request for new sync interval + ELSIF out_start = '1' THEN + verify_sync <= '1'; -- new sync interval has started; + END IF; + + IF recover_from_in_lost = '1' THEN + verify_sync <= '0'; -- after long input lost, first output_sync may get lost during catch up + END IF; + END IF; + END PROCESS; + proc_dp_verify_sync(TO_UINT(ctrl_start_bsn), ctrl_interval_size, g_block_size, clk, - out_enable, + verify_sync, out_sosi.sync, out_sosi.sop, out_sosi.bsn, @@ -492,13 +551,13 @@ BEGIN VARIABLE v_bsn_max : NATURAL; BEGIN IF rising_edge(clk) THEN - IF verify_mon_output_sync_bsn = '1' THEN + IF recover_from_in_lost = '0' THEN IF out_sop_dly = '1' THEN - v_bsn_min := TO_UINT(mon_input_current_bsn); + v_bsn_min := TO_UINT(mon_input_current_bsn) - 1; v_bsn_max := TO_UINT(mon_input_current_bsn) + c_output_nof_blocks_min + 1; ASSERT TO_UINT(mon_output_sync_bsn) >= v_bsn_min - REPORT "Wrong: mon_output_sync_bsn is behind" SEVERITY ERROR; + REPORT "Wrong: mon_output_sync_bsn is behind (" & int_to_str(TO_UINT(mon_output_sync_bsn)) & " < " & int_to_str(v_bsn_min) & ")" SEVERITY ERROR; ASSERT TO_UINT(mon_output_sync_bsn) <= v_bsn_max REPORT "Wrong: mon_output_sync_bsn is too far ahead (" & int_to_str(TO_UINT(mon_output_sync_bsn)) & " > " & int_to_str(v_bsn_max) & ")" SEVERITY ERROR;