Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/clk align axi stream slave #429

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions vunit/vhdl/verification_components/src/axi_stream_master.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ end entity;

architecture a of axi_stream_master is

signal notify_bus_process_done : std_logic := '0';
constant message_queue : queue_t := new_queue;
constant notify_request_msg : msg_type_t := new_msg_type("notify request");
constant message_queue : queue_t := new_queue;
signal notify_bus_process_done : std_logic := '0';

begin

main : process
variable request_msg : msg_t;
variable notify_msg : msg_t;
variable msg_type : msg_type_t;
begin
receive(net, master.p_actor, request_msg);
Expand All @@ -55,6 +57,8 @@ begin
elsif msg_type = wait_for_time_msg then
push(message_queue, request_msg);
elsif msg_type = wait_until_idle_msg then
notify_msg := new_msg(notify_request_msg);
push(message_queue, notify_msg);
wait on notify_bus_process_done until is_empty(message_queue);
handle_wait_until_idle(net, msg_type, request_msg);
else
Expand All @@ -65,7 +69,6 @@ begin
bus_process : process
variable msg : msg_t;
variable msg_type : msg_type_t;
variable reset_cycles : positive := 1;
begin
if drive_invalid then
tdata <= (others => drive_invalid_val);
Expand All @@ -90,7 +93,8 @@ begin
handle_sync_message(net, msg_type, msg);
-- Re-align with the clock when a wait for time message was handled, because this breaks edge alignment.
wait until rising_edge(aclk);

elsif msg_type = notify_request_msg then
-- Ignore this message, but expect it
elsif msg_type = stream_push_msg or msg_type = push_axi_stream_msg then
tvalid <= '1';
tdata <= pop_std_ulogic_vector(msg);
Expand Down
83 changes: 61 additions & 22 deletions vunit/vhdl/verification_components/src/axi_stream_slave.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,36 @@ entity axi_stream_slave is
end entity;

architecture a of axi_stream_slave is

constant notify_request_msg : msg_type_t := new_msg_type("notify request");
constant message_queue : queue_t := new_queue;
signal notify_bus_process_done : std_logic := '0';

begin

main : process
variable request_msg : msg_t;
variable notify_msg : msg_t;
variable msg_type : msg_type_t;
begin
receive(net, slave.p_actor, request_msg);
msg_type := message_type(request_msg);

if msg_type = stream_pop_msg or msg_type = pop_axi_stream_msg then
push(message_queue, request_msg);
elsif msg_type = wait_for_time_msg then
push(message_queue, request_msg);
elsif msg_type = wait_until_idle_msg then
notify_msg := new_msg(notify_request_msg);
push(message_queue, notify_msg);
wait on notify_bus_process_done until is_empty(message_queue);
handle_wait_until_idle(net, msg_type, request_msg);
else
unexpected_msg_type(msg_type);
end if;
end process;

bus_process : process
variable reply_msg, msg : msg_t;
variable msg_type : msg_type_t;
variable axi_stream_transaction : axi_stream_transaction_t(
Expand All @@ -45,32 +73,43 @@ begin
tuser(tuser'range)
);
begin
receive(net, slave.p_actor, msg);
msg_type := message_type(msg);
-- Wait for messages to arrive on the queue, posted by the process above
wait until rising_edge(aclk) and (not is_empty(message_queue));

handle_sync_message(net, msg_type, msg);
while not is_empty(message_queue) loop
msg := pop(message_queue);
msg_type := message_type(msg);

if msg_type = stream_pop_msg or msg_type = pop_axi_stream_msg then
tready <= '1';
wait until (tvalid and tready) = '1' and rising_edge(aclk);
tready <= '0';

axi_stream_transaction := (
tdata => tdata,
tlast => tlast = '1',
tkeep => tkeep,
tstrb => tstrb,
tid => tid,
tdest => tdest,
tuser => tuser
);
if msg_type = wait_for_time_msg then
handle_sync_message(net, msg_type, msg);
wait until rising_edge(aclk);
elsif msg_type = notify_request_msg then
-- Ignore this message, but expect it
elsif msg_type = stream_pop_msg or msg_type = pop_axi_stream_msg then
tready <= '1';
wait until (tvalid and tready) = '1' and rising_edge(aclk);
tready <= '0';

reply_msg := new_axi_stream_transaction_msg(axi_stream_transaction);
reply(net, msg, reply_msg);
axi_stream_transaction := (
tdata => tdata,
tlast => tlast = '1',
tkeep => tkeep,
tstrb => tstrb,
tid => tid,
tdest => tdest,
tuser => tuser
);

else
unexpected_msg_type(msg_type);
end if;
reply_msg := new_axi_stream_transaction_msg(axi_stream_transaction);
reply(net, msg, reply_msg);
else
unexpected_msg_type(msg_type);
end if;
end loop;

notify_bus_process_done <= '1';
wait until notify_bus_process_done = '1';
notify_bus_process_done <= '0';

end process;

Expand Down
23 changes: 22 additions & 1 deletion vunit/vhdl/verification_components/test/tb_axi_stream.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,27 @@ begin
pop_stream(net, slave_stream, data, last_bool);
check_equal(data, std_logic_vector'(x"77"), result("for pop stream data"));
check_true(last_bool, result("for pop stream last"));
check_equal(now - 10 ns, timestamp + 30 ns, result("for push wait time"));
check_equal(now - 10 ns, timestamp + 50 ns, result("for push wait time"));

for i in 1 to n_monitors loop
get_axi_stream_transaction(axi_stream_transaction);
check_equal(
axi_stream_transaction.tdata,
std_logic_vector'(x"77"),
result("for axi_stream_transaction.tdata")
);
check_true(axi_stream_transaction.tlast, result("for axi_stream_transaction.tlast"));
end loop;

elsif run("test single push and stalled pop with non-multiple of clock period") then
wait until rising_edge(aclk);
wait_for_time(net, slave_sync, 29 ns);
timestamp := now;
push_stream(net, master_stream, x"77", true);
pop_stream(net, slave_stream, data, last_bool);
check_equal(data, std_logic_vector'(x"77"), result("for pop stream data"));
check_true(last_bool, result("for pop stream last"));
check_equal(now - 10 ns, timestamp + 40 ns, result("for push wait time"));

for i in 1 to n_monitors loop
get_axi_stream_transaction(axi_stream_transaction);
Expand Down Expand Up @@ -261,6 +281,7 @@ begin
end loop;

wait_until_idle(net, master_sync); -- wait until all transfers are done before checking them
wait_until_idle(net, slave_sync);

for i in 0 to 7 loop
reference := pop(reference_queue);
Expand Down