Backport Memory Controller and Memory FSM from RTPS/DDS Endpoints to RTPS Builtin Endpoint. The Memory is now using a single linked list and the FSM uses Frame Field Flags. The main FSM uses check_time to initiate stale checks, and the stale checks are done in the main FSM. Testbench was modified to accomodate the changes (Previous L0 Test4 was removed and integrated in L0 Test 1).
383 lines
15 KiB
VHDL
383 lines
15 KiB
VHDL
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 stale participant handling of the rtps_builtin_endpoint. It does so by checking for the Participant Unmatch Frame.
|
|
-- It first matches 3 Participants: Participant 0 with default lease duration 100s, Participant 1 with lease duration 10s, and Participant 2 with lease duration 30s.
|
|
-- After matching the time is artificially progressed to 15s (from 0s), and the removal of Participant 1 is checked. Than the time is again artificially progressed to 101s
|
|
-- and the removal of Participant 0 and 2 is checked (in that order).
|
|
|
|
entity L0_rtps_builtin_endpoint_test5 is
|
|
end entity;
|
|
|
|
architecture testbench of L0_rtps_builtin_endpoint_test5 is
|
|
|
|
-- *CONSTANT DECLARATION*
|
|
constant MAX_REMOTE_PARTICIPANTS : natural := 3;
|
|
|
|
-- *TYPE DECLARATION*
|
|
type TEST_STAGE_TYPE is (IDLE, BUSY);
|
|
type TEST_RAM_TYPE is array (0 to (MAX_REMOTE_PARTICIPANTS*PARTICIPANT_FRAME_SIZE)-1) of std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
|
|
-- *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;
|
|
signal stim_done, check_done, test_done : std_logic := '0';
|
|
signal test_time : TIME_TYPE := TIME_ZERO;
|
|
|
|
-- *FUNCTION DECLARATION*
|
|
procedure wait_on_complete is
|
|
begin
|
|
if (test_done /= '1') then
|
|
wait until test_done = '1';
|
|
end if;
|
|
end procedure;
|
|
|
|
procedure wait_on_sent 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 : entity work.rtps_builtin_endpoint(arch)
|
|
generic map (
|
|
MAX_REMOTE_PARTICIPANTS => MAX_REMOTE_PARTICIPANTS
|
|
)
|
|
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 => test_time,
|
|
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 : RTPS_SUBMESSAGE_TYPE := DEFAULT_RTPS_SUBMESSAGE;
|
|
variable RV : RandomPType;
|
|
variable p_sn : SEQUENCENUMBER_TYPE := FIRST_SEQUENCENUMBER;
|
|
variable wr_sig : std_logic_vector(0 to NUM_ENDPOINTS-1) := (others => '0');
|
|
variable p0, p1, p2, participant : PARTICIPANT_DATA_TYPE := DEFAULT_PARTICIPANT_DATA;
|
|
|
|
alias idle_sig is <<signal uut.idle_sig : std_logic>>;
|
|
alias mem_op_done is <<signal uut.mem_op_done : std_logic>>;
|
|
|
|
-- 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_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';
|
|
wait until rising_edge(clk);
|
|
end procedure;
|
|
|
|
-- NOTE: This procedure waits until the idle_sig is high for at least
|
|
-- two consecutive clock cycles.
|
|
procedure wait_on_idle is
|
|
variable first : boolean := TRUE;
|
|
begin
|
|
loop
|
|
if (idle_sig /= '1' or mem_op_done /= '1') then
|
|
wait until idle_sig = '1' and mem_op_done = '1';
|
|
elsif (not first) then
|
|
exit;
|
|
end if;
|
|
wait until rising_edge(clk);
|
|
wait until rising_edge(clk);
|
|
first := FALSE;
|
|
end loop;
|
|
end procedure;
|
|
begin
|
|
|
|
assert (TEST_STRING = "TEST_CONFIG_1") report "user_config incompatible with testbench." severity FAILURE;
|
|
|
|
SetAlertLogName("rtps_builtin_endpoint - Level 0 - Stale Participant 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';
|
|
|
|
-- Participant 0 (Default Lease Time 100 s)
|
|
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';
|
|
|
|
-- Participant 1 (Lease Duration 10 s)
|
|
p1.guidPrefix := gen_rand_guid_prefix;
|
|
p1.nr := 1;
|
|
p1.leaseDuration := gen_duration(10,0);
|
|
p1.defaultUnicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR));
|
|
p1.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR) := '1';
|
|
p1.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER):= '1';
|
|
p1.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR) := '1';
|
|
p1.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER) := '1';
|
|
|
|
-- Participant 2 (Lease Duration 30 s)
|
|
p2.guidPrefix := gen_rand_guid_prefix;
|
|
p2.nr := 2;
|
|
p2.leaseDuration := gen_duration(30,0);
|
|
p2.defaultUnicastLocatorList := (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => gen_rand_loc_2, others => EMPTY_LOCATOR));
|
|
p2.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR) := '1';
|
|
p2.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER):= '1';
|
|
p2.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR) := '1';
|
|
p2.availableBuiltinEndpoints(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER) := '1';
|
|
|
|
Log("Initiating Test", INFO);
|
|
test_time <= TIME_ZERO;
|
|
stim_done <= '0';
|
|
start <= '0';
|
|
reset <= '1';
|
|
wait until rising_edge(clk);
|
|
wait until rising_edge(clk);
|
|
reset <= '0';
|
|
|
|
-- *PARTICIPANT*
|
|
Log("Current Time: 0s", INFO);
|
|
Log("Match Participant 0 [Default Lease 100s]", INFO);
|
|
sub.writerSN := p_sn;
|
|
participant := p0;
|
|
gen_participant_data(participant, sub.data);
|
|
gen_sentinel(sub.data);
|
|
gen_rtps_handler_out(sub, participant, stimulus);
|
|
start_test;
|
|
wait_on_sent;
|
|
wait_on_idle;
|
|
stimulus := EMPTY_TEST_PACKET;
|
|
reference := EMPTY_TEST_PACKET;
|
|
sub.data := EMPTY_TEST_PACKET;
|
|
p_sn := p_sn + 1;
|
|
|
|
Log("Match Participant 1 [Lease 10s]", INFO);
|
|
sub.writerSN := p_sn;
|
|
participant := p1;
|
|
gen_participant_data(participant, sub.data);
|
|
gen_sentinel(sub.data);
|
|
gen_rtps_handler_out(sub, participant, stimulus);
|
|
start_test;
|
|
wait_on_sent;
|
|
wait_on_idle;
|
|
stimulus := EMPTY_TEST_PACKET;
|
|
reference := EMPTY_TEST_PACKET;
|
|
sub.data := EMPTY_TEST_PACKET;
|
|
p_sn := p_sn + 1;
|
|
|
|
Log("Match Participant 2 [Lease 30s]", INFO);
|
|
sub.writerSN := p_sn;
|
|
participant := p2;
|
|
gen_participant_data(participant, sub.data);
|
|
gen_sentinel(sub.data);
|
|
gen_rtps_handler_out(sub, participant, stimulus);
|
|
start_test;
|
|
wait_on_sent;
|
|
wait_on_idle;
|
|
stimulus := EMPTY_TEST_PACKET;
|
|
reference := EMPTY_TEST_PACKET;
|
|
sub.data := EMPTY_TEST_PACKET;
|
|
p_sn := p_sn + 1;
|
|
|
|
|
|
Log("Current Time: 15 s", INFO);
|
|
test_time <= gen_duration(15,0);
|
|
participant := p1;
|
|
participant.match := UNMATCH;
|
|
push_participant_reference;
|
|
wait_on_idle;
|
|
|
|
Log("Current Time: 101 s", INFO);
|
|
test_time <= (unsigned(int(101, CDR_LONG_WIDTH)), unsigned(int(0, CDR_LONG_WIDTH)));
|
|
participant := p2;
|
|
participant.match := UNMATCH;
|
|
push_participant_reference;
|
|
participant := p0;
|
|
participant.match := UNMATCH;
|
|
push_participant_reference;
|
|
wait_on_idle;
|
|
|
|
stim_done <= '1';
|
|
wait_on_complete;
|
|
TranscriptOpen(RESULTS_FILE, APPEND_MODE);
|
|
SetTranscriptMirror;
|
|
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);
|
|
|
|
if rising_edge(clk) then
|
|
if (reset = '1') then
|
|
cnt_stim <= 0;
|
|
stim_stage <= IDLE;
|
|
packet_sent <= '1';
|
|
else
|
|
case (stim_stage) is
|
|
when IDLE =>
|
|
if (start = '1' and stimulus.length /= 0) then
|
|
stim_stage <= BUSY;
|
|
packet_sent <= '0';
|
|
end if;
|
|
when BUSY =>
|
|
if (rd_sig = '1') then
|
|
if (cnt_stim = stimulus.length-1) then
|
|
stim_stage <= IDLE;
|
|
packet_sent <= '1';
|
|
cnt_stim <= 0;
|
|
else
|
|
cnt_stim <= cnt_stim + 1;
|
|
end if;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
output_check_prc : process(all)
|
|
begin
|
|
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';
|
|
else
|
|
check_done <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
done_proc : process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if (stim_done = '1' and check_done = '1') then
|
|
test_done <= '1';
|
|
else
|
|
test_done <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
watchdog : process
|
|
begin
|
|
wait for 1 ms;
|
|
Alert("Test timeout", FAILURE);
|
|
std.env.stop;
|
|
end process;
|
|
|
|
end architecture; |