diff --git a/src/Tests/Level_0/rtps_builtin_endpoint_test5.vhd b/src/Tests/Level_0/rtps_builtin_endpoint_test5.vhd new file mode 100644 index 0000000..612a2bc --- /dev/null +++ b/src/Tests/Level_0/rtps_builtin_endpoint_test5.vhd @@ -0,0 +1,539 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library osvvm; -- Utility Library +context osvvm.OsvvmContext; + +use work.rtps_package.all; +use work.user_config.all; +use work.rtps_config_package.all; +use work.rtps_test_package.all; + +-- This testbench tests the sequence number handling of the participant, subscriber, and publisher DATA Submessages. + +entity rtps_builtin_endpoint_test5 is +end entity; + +architecture testbench of rtps_builtin_endpoint_test5 is + + -- *COMPONENT DECLARATION* + component rtps_builtin_endpoint is + port ( + clk : in std_logic; + reset : in std_logic; + empty : in std_logic; + rd : out std_logic; + data_in : in std_logic_vector(WORD_WIDTH-1 downto 0); + data_out : out std_logic_vector(WORD_WIDTH-1 downto 0); + last_word_in : in std_logic; + time : in TIME_TYPE; + endpoint_full : in std_logic_vector(0 to NUM_ENDPOINTS-1); + endpoint_wr : out std_logic_vector(0 to NUM_ENDPOINTS-1); + rtps_wr : out std_logic; + rtps_full : in std_logic; + last_word_out : out std_logic; + alive : in std_logic_vector(0 to NUM_ENDPOINTS-1) + ); + end component; + + -- *TYPE DECLARATION* + type TEST_STAGE_TYPE is (IDLE, BUSY); + + -- *SIGNAL DECLARATION* + signal clk, in_empty, rd_sig, last_word_in, last_word_out: std_logic := '0'; + signal reset : std_logic := '1'; + signal endpoint_wr, endpoint_full : std_logic_vector(0 to NUM_ENDPOINTS-1) := (others => '0'); + signal data_in, data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal stim_stage : TEST_STAGE_TYPE := IDLE; + shared variable stimulus, reference : TEST_PACKET_TYPE := EMPTY_TEST_PACKET; + signal packet_sent : std_logic := '0'; + signal cnt_stim : natural := 0; + signal start : std_logic := '0'; + shared variable SB_out : work.ScoreBoardPkg_builtin_endpoint.ScoreBoardPType; + shared variable SB_mem : work.ScoreBoardPkg_MemoryTest.ScoreBoardPType; + signal stim_done, check_done, mem_check : std_logic := '0'; + + -- *FUNCTION DECLARATION* + procedure wait_on_complete is + begin + wait until rising_edge(packet_sent); + end procedure; + + function gen_sn(input : natural) return SEQUENCENUMBER_TYPE is + variable ret : SEQUENCENUMBER_TYPE; + begin + ret(0) := (others => '0'); + ret(1) := unsigned(int(input, WORD_WIDTH)); + return ret; + end function; + +begin + + -- Unit Under Test + uut : rtps_builtin_endpoint + port map ( + clk => clk, + reset => reset, + empty => in_empty or packet_sent, + rd => rd_sig, + data_in => data_in, + data_out => data_out, + last_word_in => last_word_in, + time => TIME_ZERO, + endpoint_full => endpoint_full, + endpoint_wr => endpoint_wr, + rtps_wr => open, + rtps_full => '0', + last_word_out => last_word_out, + alive => (others => '0') + ); + + stimulus_prc : process + variable sub, sub_p, sub_s : RTPS_SUBMESSAGE_TYPE := DEFAULT_RTPS_SUBMESSAGE; + variable RV : RandomPType; + variable p0, participant : PARTICIPANT_DATA_TYPE := DEFAULT_PARTICIPANT_DATA; + variable e0, e1, endpoint : ENDPOINT_DATA_TYPE := DEFAULT_ENDPOINT_DATA; + variable p_sn, p_snp : SEQUENCENUMBER_TYPE := FIRST_SEQUENCENUMBER; + variable wr_sig : std_logic_vector(0 to NUM_ENDPOINTS-1) := (others => '0'); + + -- Wrapper to use procedure as function + impure function gen_rand_loc_2 return LOCATOR_TYPE is + variable ret : LOCATOR_TYPE := EMPTY_LOCATOR; + begin + gen_rand_loc(RV, ret); + return ret; + end function; + + impure function gen_rand_entityid_2(reader : boolean) return std_logic_vector is + variable ret : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (others => '0'); + begin + gen_rand_entityid(RV, reader, ret); + return ret; + end function; + + procedure push_endpoint_reference is + begin + -- MATCH + if (wr_sig /= (wr_sig'range => '0')) then + endpoint.match := MATCH; + gen_endpoint_match_frame(endpoint, reference); + for i in 0 to reference.length-1 loop + SB_out.Push(wr_sig & reference.last(i) & reference.data(i)); + end loop; + reference := EMPTY_TEST_PACKET; + end if; + -- UNMATCH + if ((not wr_sig) /= (wr_sig'range => '0')) then + endpoint.match := UNMATCH; + gen_endpoint_match_frame(endpoint, reference); + for i in 0 to reference.length-1 loop + SB_out.Push((not wr_sig) & reference.last(i) & reference.data(i)); + end loop; + reference := EMPTY_TEST_PACKET; + end if; + end procedure; + + procedure push_participant_reference is + variable wr_sig : std_logic_vector(NUM_ENDPOINTS-1 downto 0) := (others => '1'); + begin + gen_participant_match_frame(participant, reference); + for i in 0 to reference.length-1 loop + SB_out.Push(wr_sig & reference.last(i) & reference.data(i)); + end loop; + reference := EMPTY_TEST_PACKET; + end procedure; + + impure function gen_rand_guid_prefix return GUIDPREFIX_TYPE is + variable ret : GUIDPREFIX_TYPE; + begin + ret := (0 => RV.RandSlv(WORD_WIDTH), 1 => RV.RandSlv(WORD_WIDTH), 2 => RV.RandSlv(WORD_WIDTH)); + return ret; + end function; + + procedure start_test is + begin + start <= '1'; + wait until rising_edge(clk); + start <= '0'; + mem_check <= '0'; + wait until rising_edge(clk); + end procedure; + begin + + assert (TEST_STRING = "TEST_CONFIG_1") report "user_config incompatible with testbench." severity FAILURE; + + SetAlertLogName("L0-rtps_builtin_endpoint-sequence_number_handling"); + SetAlertEnable(FAILURE, TRUE); + SetAlertEnable(ERROR, TRUE); + SetAlertEnable(WARNING, TRUE); + SetLogEnable(DEBUG, FALSE); + SetLogEnable(PASSED, FALSE); + SetLogEnable(INFO, TRUE); + RV.InitSeed(RV'instance_name); + + -- Participant RTPS Submessage + sub := DEFAULT_RTPS_SUBMESSAGE; + sub.submessageID := SID_DATA; + sub.writerId := ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER; + sub.readerId := ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR; + sub.flags(SUBMESSAGE_DATA_FLAG_POS) := '1'; + + -- Publisher Endpoint RTPS Submessage + sub_p := DEFAULT_RTPS_SUBMESSAGE; + sub_p.submessageID := SID_DATA; + sub_p.writerId := ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER; + sub_p.readerId := ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR; + sub_p.flags(SUBMESSAGE_DATA_FLAG_POS) := '1'; + + -- Subscriber Endpoint RTPS Submessage + sub_s := DEFAULT_RTPS_SUBMESSAGE; + sub_s.submessageID := SID_DATA; + sub_s.writerId := ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER; + sub_s.readerId := ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR; + sub_s.flags(SUBMESSAGE_DATA_FLAG_POS) := '1'; + + -- Participant 0 + p0.guidPrefix := gen_rand_guid_prefix; + p0.nr := 0; + p0.defaultUnicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR)); + p0.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR) := '1'; + p0.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER):= '1'; + p0.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR) := '1'; + p0.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER) := '1'; + + e0.participant := p0; + e0.topic_name := ENDPOINT_TOPIC(2); + e0.type_name := ENDPOINT_TYPE(2); + e0.entityId := gen_rand_entityid_2(FALSE); + + e1.participant := p0; + e1.topic_name := ENDPOINT_TOPIC(2); + e1.type_name := ENDPOINT_TYPE(2); + e1.entityId := gen_rand_entityid_2(FALSE); + + Log("Initiating Test", INFO); + mem_check <= '1'; + stim_done <= '0'; + start <= '0'; + reset <= '1'; + wait until rising_edge(clk); + wait until rising_edge(clk); + reset <= '0'; + + -- *PARTICIPANT* + + Log("Match Participant 0 [SN 1]", INFO); + sub.writerSN := gen_sn(1); + participant := p0; + participant.nr := 0; + participant.match := MATCH; + gen_participant_data(participant, sub.data); + gen_sentinel(sub.data); + gen_rtps_handler_out(sub, participant, stimulus); + SB_mem.Push(gen_participant_mem_frame(participant)); + start_test; + mem_check <= '1'; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub.data := EMPTY_TEST_PACKET; + + p0.defaultUnicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR)); + + Log("Update Participant 0 [SN 2]", INFO); + sub.writerSN := gen_sn(2); + participant := p0; + participant.nr := 0; + participant.match := MATCH; + gen_participant_data(participant, sub.data); + gen_sentinel(sub.data); + gen_rtps_handler_out(sub, participant, stimulus); + SB_mem.Push(gen_participant_mem_frame(participant)); + start_test; + mem_check <= '1'; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub.data := EMPTY_TEST_PACKET; + + p0.defaultUnicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR)); + + Log("Update Participant 0 [SN 5]", INFO); + sub.writerSN := gen_sn(5); + participant := p0; + participant.nr := 0; + participant.match := MATCH; + gen_participant_data(participant, sub.data); + gen_sentinel(sub.data); + gen_rtps_handler_out(sub, participant, stimulus); + SB_mem.Push(gen_participant_mem_frame(participant)); + start_test; + mem_check <= '1'; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub.data := EMPTY_TEST_PACKET; + + Log("Ignore Update Participant 0 [SN 3]", INFO); + sub.writerSN := gen_sn(3); + participant := p0; + participant.nr := 0; + participant.match := MATCH; + participant.defaultUnicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR)); + gen_participant_data(participant, sub.data); + gen_sentinel(sub.data); + gen_rtps_handler_out(sub, participant, stimulus); + SB_mem.Push(gen_participant_mem_frame(p0)); + start_test; + mem_check <= '1'; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub.data := EMPTY_TEST_PACKET; + + -- *PUBLISHER* + + Log("Match Writer Participant 0 [SN 1]", INFO); + sub_p.writerSN := gen_sn(1); + endpoint := e0; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_p.data); + gen_sentinel(sub_p.data); + gen_rtps_handler_out(sub_p, endpoint, stimulus); + wr_sig := (2 => '1', others => '0'); + push_endpoint_reference; + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_p.data := EMPTY_TEST_PACKET; + + e0.unicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR)); + + Log("Update Writer Participant 0 [SN 2]", INFO); + sub_p.writerSN := gen_sn(2); + endpoint := e0; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_p.data); + gen_sentinel(sub_p.data); + gen_rtps_handler_out(sub_p, endpoint, stimulus); + wr_sig := (2 => '1', others => '0'); + push_endpoint_reference; + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_p.data := EMPTY_TEST_PACKET; + + Log("Ignore Update Writer Participant 0 [SN 5]", INFO); + sub_p.writerSN := gen_sn(5); + endpoint := e0; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_p.data); + gen_sentinel(sub_p.data); + gen_rtps_handler_out(sub_p, endpoint, stimulus); + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_p.data := EMPTY_TEST_PACKET; + + Log("Ignore Update Writer Participant 0 [SN 1]", INFO); + sub_p.writerSN := gen_sn(1); + endpoint := e0; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_p.data); + gen_sentinel(sub_p.data); + gen_rtps_handler_out(sub_p, endpoint, stimulus); + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_p.data := EMPTY_TEST_PACKET; + + -- *SUBSCRIBER* + + Log("Match Reader Participant 0 [SN 1]", INFO); + sub_s.writerSN := gen_sn(1); + endpoint := e1; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_s.data); + gen_sentinel(sub_s.data); + gen_rtps_handler_out(sub_s, endpoint, stimulus); + wr_sig := (NUM_READERS+2 => '1', others => '0'); + push_endpoint_reference; + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_s.data := EMPTY_TEST_PACKET; + + e1.unicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR)); + + Log("Update Reader Participant 0 [SN 2]", INFO); + sub_s.writerSN := gen_sn(2); + endpoint := e1; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_s.data); + gen_sentinel(sub_s.data); + gen_rtps_handler_out(sub_s, endpoint, stimulus); + wr_sig := (NUM_READERS+2 => '1', others => '0'); + push_endpoint_reference; + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_s.data := EMPTY_TEST_PACKET; + + Log("Ignore Update Reader Participant 0 [SN 5]", INFO); + sub_s.writerSN := gen_sn(5); + endpoint := e1; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_s.data); + gen_sentinel(sub_s.data); + gen_rtps_handler_out(sub_s, endpoint, stimulus); + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_s.data := EMPTY_TEST_PACKET; + + Log("Ignore Update Reader Participant 0 [SN 1]", INFO); + sub_s.writerSN := gen_sn(1); + endpoint := e1; + endpoint.participant:= p0; + gen_endpoint_data(endpoint, sub_s.data); + gen_sentinel(sub_s.data); + gen_rtps_handler_out(sub_s, endpoint, stimulus); + start_test; + wait_on_complete; + stimulus := EMPTY_TEST_PACKET; + reference := EMPTY_TEST_PACKET; + sub_s.data := EMPTY_TEST_PACKET; + + TranscriptOpen(RESULTS_FILE, APPEND_MODE); + SetTranscriptMirror; + stim_done <= '1'; + wait until check_done = '1'; + AlertIf((not SB_out.empty) or (not SB_mem.empty), "Incomplete test run"); + ReportAlerts; + TranscriptClose; + std.env.stop; + wait; + end process; + + clock_prc : process + begin + clk <= '0'; + wait for 25 ns; + clk <= '1'; + wait for 25 ns; + end process; + + in_empty_prc : process + begin + in_empty <= '0'; + wait until rd_sig = '1'; + wait until rising_edge(clk); + in_empty <= '1'; + wait until rising_edge(clk); + end process; + + endpoint_full_prc : process + begin + endpoint_full <= (others => '0'); + wait until (or endpoint_wr) = '1'; + wait until rising_edge(clk); + endpoint_full <= (others => '1'); + wait until rising_edge(clk); + end process; + + alert_prc : process(all) + begin + if rising_edge(clk) then + alertif(in_empty = '1' and rd_sig = '1', "Input FIFO read signal high while empty signal high", ERROR); + alertif(endpoint_full /= (0 to NUM_ENDPOINTS-1 => '0') and (endpoint_wr /= (0 to NUM_ENDPOINTS-1 => '0')), "Endpoint FIFO write signal high while full signal high", ERROR); + end if; + end process; + + input_prc : process(all) + begin + data_in <= stimulus.data(cnt_stim); + last_word_in <= stimulus.last(cnt_stim); + case (stim_stage) is + when IDLE => + packet_sent <= '1'; + when BUSY => + packet_sent <= '0'; + end case; + + if rising_edge(clk) then + if (reset = '1') then + cnt_stim <= 0; + stim_stage <= IDLE; + else + case (stim_stage) is + when IDLE => + if (start = '1') then + stim_stage <= BUSY; + cnt_stim <= 0; + end if; + when BUSY => + if (cnt_stim = stimulus.length) then + stim_stage <= IDLE; + elsif (rd_sig = '1') then + cnt_stim <= cnt_stim + 1; + end if; + end case; + end if; + end if; + end process; + + output_check_prc : process(all) + begin + check_done <= '0'; + if rising_edge(clk) then + if (endpoint_wr /= (0 to NUM_ENDPOINTS-1 => '0')) then + SB_out.Check(endpoint_wr & last_word_out & data_out); + end if; + if (stim_done = '1' and SB_out.empty) then + check_done <= '1'; + end if; + end if; + end process; + + mem_check_prc : process + alias mem is <>; + alias mem_op_done is <>; + variable reference : TEST_PARTICIPANT_MEMORY_FRAME_TYPE; + begin + -- SAFEGUARD: (Prevent Fall-through Behavior) + if (reset /= '0') then + wait until reset = '0'; + end if; + -- NOTE: The first read after the packet is sent signifies that the State Machine has begun processing the next packet. + -- The memory operation that could still be in progress is the last one concerning the last sent packet. + wait on packet_sent until (packet_sent = '1' and mem_check = '1'); + if (rd_sig /= '1') then + wait until rd_sig = '1'; + end if; + if (mem_op_done /= '1') then + wait until mem_op_done = '1'; + end if; + if (not SB_mem.empty) then + SB_mem.Pop(reference); + for i in 0 to reference'length-1 loop + AffirmIf(?? (mem(reference(i).addr) ?= reference(i).data), "Address: " & integer'image(reference(i).addr) & " Received: " & to_hstring(mem(reference(i).addr)) & " Expected: " & to_hstring(reference(i).data)); + end loop; + end if; + end process; + + watchdog : process + begin + wait for 1 ms; + Alert("Test timeout", FAILURE); + std.env.stop; + end process; + +end architecture; \ No newline at end of file diff --git a/src/Tests/testbench.pro b/src/Tests/testbench.pro index a81c502..f44183a 100644 --- a/src/Tests/testbench.pro +++ b/src/Tests/testbench.pro @@ -19,10 +19,12 @@ analyze Level_0/rtps_builtin_endpoint_test1.vhd analyze Level_0/rtps_builtin_endpoint_test2.vhd analyze Level_0/rtps_builtin_endpoint_test3.vhd analyze Level_0/rtps_builtin_endpoint_test4.vhd +analyze Level_0/rtps_builtin_endpoint_test5.vhd #simulate rtps_handler_test1 #simulate rtps_handler_test2 #simulate rtps_builtin_endpoint_test1 #simulate rtps_builtin_endpoint_test2 #simulate rtps_builtin_endpoint_test3 -simulate rtps_builtin_endpoint_test4 \ No newline at end of file +#simulate rtps_builtin_endpoint_test4 +simulate rtps_builtin_endpoint_test5 \ No newline at end of file