diff --git a/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd b/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd index 73709b10b..40f0ddc85 100644 --- a/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd @@ -183,6 +183,7 @@ package axi_stream_pkg is constant push_axi_stream_msg : msg_type_t := new_msg_type("push axi stream"); constant pop_axi_stream_msg : msg_type_t := new_msg_type("pop axi stream"); + constant check_axi_stream_msg : msg_type_t := new_msg_type("check axi stream"); constant axi_stream_transaction_msg : msg_type_t := new_msg_type("axi stream transaction"); alias axi_stream_reference_t is msg_t; @@ -255,7 +256,8 @@ package axi_stream_pkg is tid : std_logic_vector := ""; tdest : std_logic_vector := ""; tuser : std_logic_vector := ""; - msg : string := "" + msg : string := ""; + blocking : boolean := true ); type axi_stream_transaction_t is record @@ -667,7 +669,8 @@ package body axi_stream_pkg is tid : std_logic_vector := ""; tdest : std_logic_vector := ""; tuser : std_logic_vector := ""; - msg : string := "" + msg : string := ""; + blocking : boolean := true ) is variable got_tdata : std_logic_vector(data_length(axi_stream)-1 downto 0); variable got_tlast : std_logic; @@ -676,24 +679,49 @@ package body axi_stream_pkg is variable got_tid : std_logic_vector(id_length(axi_stream)-1 downto 0); variable got_tdest : std_logic_vector(dest_length(axi_stream)-1 downto 0); variable got_tuser : std_logic_vector(user_length(axi_stream)-1 downto 0); + variable check_msg : msg_t := new_msg(check_axi_stream_msg); + variable normalized_data : std_logic_vector(data_length(axi_stream)-1 downto 0) := (others => '0'); + variable normalized_keep : std_logic_vector(data_length(axi_stream)/8-1 downto 0) := (others => '0'); + variable normalized_strb : std_logic_vector(data_length(axi_stream)/8-1 downto 0) := (others => '0'); + variable normalized_id : std_logic_vector(id_length(axi_stream)-1 downto 0) := (others => '0'); + variable normalized_dest : std_logic_vector(dest_length(axi_stream)-1 downto 0) := (others => '0'); + variable normalized_user : std_logic_vector(user_length(axi_stream)-1 downto 0) := (others => '0'); begin - pop_axi_stream(net, axi_stream, got_tdata, got_tlast, got_tkeep, got_tstrb, got_tid, got_tdest, got_tuser); - check_equal(got_tdata, expected, msg); - check_equal(got_tlast, tlast, msg); - if tkeep'length > 0 then - check_equal(got_tkeep, tkeep, msg); - end if; - if tstrb'length > 0 then - check_equal(got_tstrb, tstrb, msg); - end if; - if tid'length > 0 then - check_equal(got_tid, tid, msg); - end if; - if tdest'length > 0 then - check_equal(got_tdest, tdest, msg); - end if; - if tuser'length > 0 then - check_equal(got_tuser, tuser, msg); + if blocking then + pop_axi_stream(net, axi_stream, got_tdata, got_tlast, got_tkeep, got_tstrb, got_tid, got_tdest, got_tuser); + check_equal(got_tdata, expected, "TDATA mismatch, " & msg); + check_equal(got_tlast, tlast, "TLAST mismatch, " & msg); + if tkeep'length > 0 then + check_equal(got_tkeep, tkeep, "TKEEP mismatch, " & msg); + end if; + if tstrb'length > 0 then + check_equal(got_tstrb, tstrb, "TSTRB mismatch, " & msg); + end if; + if tid'length > 0 then + check_equal(got_tid, tid, "TID mismatch, " & msg); + end if; + if tdest'length > 0 then + check_equal(got_tdest, tdest, "TDEST mismatch, " & msg); + end if; + if tuser'length > 0 then + check_equal(got_tuser, tuser, "TUSER mismatch, " & msg); + end if; + else + push_string(check_msg, msg); + normalized_data(expected'length-1 downto 0) := expected; + push_std_ulogic_vector(check_msg, normalized_data); + push_std_ulogic(check_msg, tlast); + normalized_keep(tkeep'length-1 downto 0) := tkeep; + push_std_ulogic_vector(check_msg, normalized_keep); + normalized_strb(tstrb'length-1 downto 0) := tstrb; + push_std_ulogic_vector(check_msg, normalized_strb); + normalized_id(tid'length-1 downto 0) := tid; + push_std_ulogic_vector(check_msg, normalized_id); + normalized_dest(tdest'length-1 downto 0) := tdest; + push_std_ulogic_vector(check_msg, normalized_dest); + normalized_user(tuser'length-1 downto 0) := tuser; + push_std_ulogic_vector(check_msg, normalized_user); + send(net, axi_stream.p_actor, check_msg); end if; end procedure; diff --git a/vunit/vhdl/verification_components/src/axi_stream_slave.vhd b/vunit/vhdl/verification_components/src/axi_stream_slave.vhd index 27d6cc252..bc36796b7 100644 --- a/vunit/vhdl/verification_components/src/axi_stream_slave.vhd +++ b/vunit/vhdl/verification_components/src/axi_stream_slave.vhd @@ -12,6 +12,7 @@ context work.com_context; use work.stream_slave_pkg.all; use work.axi_stream_pkg.all; use work.sync_pkg.all; +use work.string_ptr_pkg.all; entity axi_stream_slave is generic ( @@ -49,6 +50,8 @@ begin if msg_type = stream_pop_msg or msg_type = pop_axi_stream_msg then push(message_queue, request_msg); + elsif msg_type = check_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 @@ -64,6 +67,7 @@ begin bus_process : process variable reply_msg, msg : msg_t; variable msg_type : msg_type_t; + variable report_msg : string_ptr_t; variable axi_stream_transaction : axi_stream_transaction_t( tdata(tdata'range), tkeep(tkeep'range), @@ -102,6 +106,29 @@ begin reply_msg := new_axi_stream_transaction_msg(axi_stream_transaction); reply(net, msg, reply_msg); + elsif msg_type = check_axi_stream_msg then + tready <= '1'; + wait until (tvalid and tready) = '1' and rising_edge(aclk); + tready <= '0'; + + report_msg := new_string_ptr(pop_string(msg)); + check_equal(tdata, pop_std_ulogic_vector(msg), "TDATA mismatch, " & to_string(report_msg)); + check_equal(tlast, pop_std_ulogic(msg), "TLAST mismatch, " & to_string(report_msg)); + if tkeep'length > 0 then + check_equal(tkeep, pop_std_ulogic_vector(msg), "TKEEP mismatch, " & to_string(report_msg)); + end if; + if tstrb'length > 0 then + check_equal(tstrb, pop_std_ulogic_vector(msg), "TSTRB mismatch, " & to_string(report_msg)); + end if; + if tid'length > 0 then + check_equal(tid, pop_std_ulogic_vector(msg), "TID mismatch, " & to_string(report_msg)); + end if; + if tdest'length > 0 then + check_equal(tdest, pop_std_ulogic_vector(msg), "TDEST mismatch, " & to_string(report_msg)); + end if; + if tuser'length > 0 then + check_equal(tuser, pop_std_ulogic_vector(msg), "TUSER mismatch, " & to_string(report_msg)); + end if; else unexpected_msg_type(msg_type); end if; diff --git a/vunit/vhdl/verification_components/test/tb_axi_stream.vhd b/vunit/vhdl/verification_components/test/tb_axi_stream.vhd index 5d8b0039d..0b28f82a9 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_stream.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_stream.vhd @@ -316,16 +316,101 @@ begin mock(mocklogger); check_axi_stream(net, slave_axi_stream, x"12", '1', "1", "1", x"23", x"34", x"45", "checking axi stream"); - check_log(mocklogger, "checking axi stream - Got 0001_0001 (17). Expected 0001_0010 (18).", error); - check_log(mocklogger, "checking axi stream - Got 0. Expected 1.", error); - check_log(mocklogger, "checking axi stream - Got 0 (0). Expected 1 (1).", error); - check_log(mocklogger, "checking axi stream - Got 0 (0). Expected 1 (1).", error); - check_log(mocklogger, "checking axi stream - Got 0010_0010 (34). Expected 0010_0011 (35).", error); - check_log(mocklogger, "checking axi stream - Got 0011_0011 (51). Expected 0011_0100 (52).", error); - check_log(mocklogger, "checking axi stream - Got 0100_0100 (68). Expected 0100_0101 (69).", error); + check_log(mocklogger, "TDATA mismatch, checking axi stream - Got 0001_0001 (17). Expected 0001_0010 (18).", error); + check_log(mocklogger, "TLAST mismatch, checking axi stream - Got 0. Expected 1.", error); + check_log(mocklogger, "TKEEP mismatch, checking axi stream - Got 0 (0). Expected 1 (1).", error); + check_log(mocklogger, "TSTRB mismatch, checking axi stream - Got 0 (0). Expected 1 (1).", error); + check_log(mocklogger, "TID mismatch, checking axi stream - Got 0010_0010 (34). Expected 0010_0011 (35).", error); + check_log(mocklogger, "TDEST mismatch, checking axi stream - Got 0011_0011 (51). Expected 0011_0100 (52).", error); + check_log(mocklogger, "TUSER mismatch, checking axi stream - Got 0100_0100 (68). Expected 0100_0101 (69).", error); unmock(mocklogger); + elsif run("test back-to-back passing check") then + wait until rising_edge(aclk); + timestamp := now; + + last := '0'; + for i in 3 to 14 loop + if i = 14 then + last := '1'; + end if; + push_axi_stream(net, master_axi_stream, + tdata => std_logic_vector(to_unsigned(i, 8)), + tlast => last, + tkeep => "1", + tstrb => "1", + tid => std_logic_vector(to_unsigned(42, 8)), + tdest => std_logic_vector(to_unsigned(i+1, 8)), + tuser => std_logic_vector(to_unsigned(i*2, 8))); + end loop; + + last := '0'; + for i in 3 to 14 loop + if i = 14 then + last := '1'; + end if; + check_axi_stream(net, slave_axi_stream, + expected => std_logic_vector(to_unsigned(i, 8)), + tlast => last, + tkeep => "1", + tstrb => "1", + tid => std_logic_vector(to_unsigned(42, 8)), + tdest => std_logic_vector(to_unsigned(i+1, 8)), + tuser => std_logic_vector(to_unsigned(i*2, 8)), + msg => "check blocking", + blocking => false); + end loop; + + check_equal(now, timestamp, result(" setting up transaction stalled")); + + wait_until_idle(net, as_sync(slave_axi_stream)); + check_equal(now, timestamp + (12+1)*10 ns, " transaction time incorrect"); + + elsif run("test back-to-back failing check") then + wait until rising_edge(aclk); + timestamp := now; + + push_axi_stream(net, master_axi_stream, + tdata => std_logic_vector(to_unsigned(3, 8)), + tlast => '1', + tkeep => "0", + tstrb => "0", + tid => std_logic_vector(to_unsigned(42, 8)), + tdest => std_logic_vector(to_unsigned(4, 8)), + tuser => std_logic_vector(to_unsigned(7, 8))); + + check_axi_stream(net, slave_axi_stream, + expected => std_logic_vector(to_unsigned(6, 8)), + tlast => '0', + tkeep => "1", + tstrb => "1", + tid => std_logic_vector(to_unsigned(44, 8)), + tdest => std_logic_vector(to_unsigned(5, 8)), + tuser => std_logic_vector(to_unsigned(8, 8)), + msg => "check non-blocking", + blocking => false); + + check_equal(now, timestamp, result(" setting up transaction stalled")); + + wait until rising_edge(aclk); + mocklogger := get_logger("check"); + mock(mocklogger); + + wait until rising_edge(aclk) and tvalid = '1'; + + check_log(mocklogger, "TDATA mismatch, check non-blocking - Got 0000_0011 (3). Expected 0000_0110 (6).", error); + check_log(mocklogger, "TLAST mismatch, check non-blocking - Got 1. Expected 0.", error); + check_log(mocklogger, "TKEEP mismatch, check non-blocking - Got 0 (0). Expected 1 (1).", error); + check_log(mocklogger, "TSTRB mismatch, check non-blocking - Got 0 (0). Expected 1 (1).", error); + check_log(mocklogger, "TID mismatch, check non-blocking - Got 0010_1010 (42). Expected 0010_1100 (44).", error); + check_log(mocklogger, "TDEST mismatch, check non-blocking - Got 0000_0100 (4). Expected 0000_0101 (5).", error); + check_log(mocklogger, "TUSER mismatch, check non-blocking - Got 0000_0111 (7). Expected 0000_1000 (8).", error); + + unmock(mocklogger); + + check_equal(now, timestamp + 20 ns, " transaction time incorrect"); + end if; test_runner_cleanup(runner); end process;