Skip to content

Commit 3515624

Browse files
committed
Add support for non-byte tdata widths in AXI stream VCs.
This is non-standard and must explicitly be enabled. The difference from the standard implementation is with respect to the length of tkeep and tstrb which is calculated as (tdata'length + 7) / 8 rather than tdata'length / 8 .
1 parent 4e30fa1 commit 3515624

File tree

9 files changed

+159
-77
lines changed

9 files changed

+159
-77
lines changed

docs/news.d/1127.feature.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The AXI stream standard requires tdata to be a multiple of 8 bits. Updated AXI stream VCs to also support other bit widths.
2+
This affects tkeep and tstrb which widths are set to (tdata'length + 7) / 8 rather than tdata'length / 8. This new feature
3+
is disabled by default and is enabled by setting the allow_arbitrary_data_length to true in the VC constructor call.

vunit/vhdl/verification_components/run.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def gen_avalon_master_tests(obj, *args):
134134
for id_length in [0, 8]:
135135
for dest_length in [0, 8]:
136136
for user_length in [0, 8]:
137-
for data_length in [8, 16]:
137+
for data_length in [0, 3, 8, 11, 16]:
138138
for test in TB_AXI_STREAM.get_tests("*check"):
139139
test.add_config(
140140
name=f"id_l={id_length} dest_l={dest_length} user_l={user_length} data_l={data_length}",
@@ -150,7 +150,7 @@ def gen_avalon_master_tests(obj, *args):
150150

151151
TB_AXI_STREAM_PROTOCOL_CHECKER = LIB.test_bench("tb_axi_stream_protocol_checker")
152152

153-
for data_length in [0, 8, 32]:
153+
for data_length in [0, 3, 8, 11, 32]:
154154
for test in TB_AXI_STREAM_PROTOCOL_CHECKER.get_tests("*passing*tdata*"):
155155
test.add_config(name="data_length=%d" % data_length, generics=dict(data_length=data_length))
156156

vunit/vhdl/verification_components/src/axi_stream_master.vhd

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ entity axi_stream_master is
3737
tready : in std_logic := '1';
3838
tdata : out std_logic_vector(data_length(master)-1 downto 0) := (others => '0');
3939
tlast : out std_logic := '0';
40-
tkeep : out std_logic_vector(data_length(master)/8-1 downto 0) := (others => '1');
41-
tstrb : out std_logic_vector(data_length(master)/8-1 downto 0) := (others => '1');
40+
tkeep : out std_logic_vector(keep_strb_length(master)-1 downto 0) := (others => '1');
41+
tstrb : out std_logic_vector(keep_strb_length(master)-1 downto 0) := (others => '1');
4242
tid : out std_logic_vector(id_length(master)-1 downto 0) := (others => '0');
4343
tdest : out std_logic_vector(dest_length(master)-1 downto 0) := (others => '0');
4444
tuser : out std_logic_vector(user_length(master)-1 downto 0) := (others => '0')
@@ -55,8 +55,8 @@ architecture a of axi_stream_master is
5555

5656

5757
procedure drive_invalid_output(signal l_tdata : out std_logic_vector(data_length(master)-1 downto 0);
58-
signal l_tkeep : out std_logic_vector(data_length(master)/8-1 downto 0);
59-
signal l_tstrb : out std_logic_vector(data_length(master)/8-1 downto 0);
58+
signal l_tkeep : out std_logic_vector(keep_strb_length(master)-1 downto 0);
59+
signal l_tstrb : out std_logic_vector(keep_strb_length(master)-1 downto 0);
6060
signal l_tid : out std_logic_vector(id_length(master)-1 downto 0);
6161
signal l_tdest : out std_logic_vector(dest_length(master)-1 downto 0);
6262
signal l_tuser : out std_logic_vector(user_length(master)-1 downto 0))

vunit/vhdl/verification_components/src/axi_stream_monitor.vhd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ entity axi_stream_monitor is
2424
tready : in std_logic := '1';
2525
tdata : in std_logic_vector(data_length(monitor) - 1 downto 0);
2626
tlast : in std_logic := '1';
27-
tkeep : in std_logic_vector(data_length(monitor)/8-1 downto 0) := (others => '1');
28-
tstrb : in std_logic_vector(data_length(monitor)/8-1 downto 0) := (others => 'U');
27+
tkeep : in std_logic_vector(keep_strb_length(monitor)-1 downto 0) := (others => '1');
28+
tstrb : in std_logic_vector(keep_strb_length(monitor)-1 downto 0) := (others => 'U');
2929
tid : in std_logic_vector(id_length(monitor)-1 downto 0) := (others => '0');
3030
tdest : in std_logic_vector(dest_length(monitor)-1 downto 0) := (others => '0');
3131
tuser : in std_logic_vector(user_length(monitor)-1 downto 0) := (others => '0')

vunit/vhdl/verification_components/src/axi_stream_pkg.vhd

Lines changed: 95 additions & 32 deletions
Large diffs are not rendered by default.

vunit/vhdl/verification_components/src/axi_stream_protocol_checker.vhd

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ entity axi_stream_protocol_checker is
3030
tready : in std_logic := '1';
3131
tdata : in std_logic_vector(data_length(protocol_checker) - 1 downto 0);
3232
tlast : in std_logic := '1';
33-
tkeep : in std_logic_vector(data_length(protocol_checker)/8-1 downto 0) := (others => '1');
34-
tstrb : in std_logic_vector(data_length(protocol_checker)/8-1 downto 0) := (others => 'U');
33+
tkeep : in std_logic_vector(keep_strb_length(protocol_checker)-1 downto 0) := (others => '1');
34+
tstrb : in std_logic_vector(keep_strb_length(protocol_checker)-1 downto 0) := (others => 'U');
3535
tid : in std_logic_vector(id_length(protocol_checker)-1 downto 0) := (others => '0');
3636
tdest : in std_logic_vector(dest_length(protocol_checker)-1 downto 0) := (others => '0');
3737
tuser : in std_logic_vector(user_length(protocol_checker)-1 downto 0) := (others => '0')
@@ -85,7 +85,7 @@ architecture a of axi_stream_protocol_checker is
8585
ret := data;
8686
for i in keep'range loop
8787
if keep(i) = '0' or strb(i) = '0' then
88-
ret(i*8+7 downto i*8) := (others => '0');
88+
ret(minimum(i*8+7, ret'left) downto i*8) := (others => '0');
8989
end if;
9090
end loop;
9191
return ret;

vunit/vhdl/verification_components/src/axi_stream_slave.vhd

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ entity axi_stream_slave is
3434
tready : out std_logic := '0';
3535
tdata : in std_logic_vector(data_length(slave)-1 downto 0);
3636
tlast : in std_logic := '1';
37-
tkeep : in std_logic_vector(data_length(slave)/8-1 downto 0) := (others => '1');
38-
tstrb : in std_logic_vector(data_length(slave)/8-1 downto 0) := (others => 'U');
37+
tkeep : in std_logic_vector(keep_strb_length(slave)-1 downto 0) := (others => '1');
38+
tstrb : in std_logic_vector(keep_strb_length(slave)-1 downto 0) := (others => 'U');
3939
tid : in std_logic_vector(id_length(slave)-1 downto 0) := (others => '0');
4040
tdest : in std_logic_vector(dest_length(slave)-1 downto 0) := (others => '0');
4141
tuser : in std_logic_vector(user_length(slave)-1 downto 0) := (others => '0')
@@ -146,7 +146,8 @@ begin
146146
mismatch := false;
147147
for idx in tkeep'range loop
148148
if tkeep(idx) and tstrb_resolved(idx) then
149-
mismatch := tdata(8 * idx + 7 downto 8 * idx) /= expected_tdata(8 * idx + 7 downto 8 * idx);
149+
mismatch := tdata(minimum(8 * idx + 7, tdata'left) downto 8 * idx) /=
150+
expected_tdata(minimum(8 * idx + 7, tdata'left) downto 8 * idx);
150151
exit when mismatch;
151152
end if;
152153
end loop;

vunit/vhdl/verification_components/test/tb_axi_stream.vhd

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use osvvm.RandomPkg.all;
2323
entity tb_axi_stream is
2424
generic(
2525
runner_cfg : string;
26-
g_data_length : positive := 8;
26+
g_data_length : natural := 8;
2727
g_id_length : natural := 8;
2828
g_dest_length : natural := 8;
2929
g_user_length : natural := 8;
@@ -42,29 +42,31 @@ architecture a of tb_axi_stream is
4242
constant master_axi_stream : axi_stream_master_t := new_axi_stream_master(
4343
data_length => g_data_length, id_length => g_id_length, dest_length => g_dest_length, user_length => g_user_length,
4444
stall_config => master_stall_config, logger => get_logger("master"), actor => new_actor("master"),
45-
monitor => default_axi_stream_monitor, protocol_checker => default_axi_stream_protocol_checker
45+
monitor => default_axi_stream_monitor, protocol_checker => default_axi_stream_protocol_checker,
46+
allow_arbitrary_data_length => g_data_length mod 8 /= 0
4647
);
4748
constant master_stream : stream_master_t := as_stream(master_axi_stream);
4849
constant master_sync : sync_handle_t := as_sync(master_axi_stream);
4950

5051
constant slave_axi_stream : axi_stream_slave_t := new_axi_stream_slave(
5152
data_length => g_data_length, id_length => g_id_length, dest_length => g_dest_length, user_length => g_user_length,
5253
stall_config => slave_stall_config, logger => get_logger("slave"), actor => new_actor("slave"),
53-
monitor => default_axi_stream_monitor, protocol_checker => default_axi_stream_protocol_checker
54+
monitor => default_axi_stream_monitor, protocol_checker => default_axi_stream_protocol_checker,
55+
allow_arbitrary_data_length => g_data_length mod 8 /= 0
5456
);
5557
constant slave_stream : stream_slave_t := as_stream(slave_axi_stream);
5658
constant slave_sync : sync_handle_t := as_sync(slave_axi_stream);
5759

5860
constant monitor : axi_stream_monitor_t := new_axi_stream_monitor(
5961
data_length => g_data_length, id_length => g_id_length, dest_length => g_dest_length, user_length => g_user_length,
6062
logger => get_logger("monitor"), actor => new_actor("monitor"),
61-
protocol_checker => default_axi_stream_protocol_checker
63+
protocol_checker => default_axi_stream_protocol_checker,
64+
allow_arbitrary_data_length => g_data_length mod 8 /= 0
6265
);
6366

6467
constant protocol_checker : axi_stream_protocol_checker_t := new_axi_stream_protocol_checker(
6568
data_length => g_data_length, id_length => g_id_length, dest_length => g_dest_length, user_length => g_user_length,
66-
logger => get_logger("protocol_checker"),
67-
max_waits => 8
69+
logger => get_logger("protocol_checker"), max_waits => 8, allow_arbitrary_data_length => g_data_length mod 8 /= 0
6870
);
6971

7072
constant n_monitors : natural := 3;
@@ -75,8 +77,8 @@ architecture a of tb_axi_stream is
7577
signal tready : std_logic;
7678
signal tdata : std_logic_vector(data_length(slave_axi_stream)-1 downto 0);
7779
signal tlast : std_logic;
78-
signal tkeep, tkeep_from_master : std_logic_vector(data_length(slave_axi_stream)/8-1 downto 0);
79-
signal tstrb, tstrb_from_master : std_logic_vector(data_length(slave_axi_stream)/8-1 downto 0);
80+
signal tkeep, tkeep_from_master : std_logic_vector(keep_strb_length(slave_axi_stream)-1 downto 0);
81+
signal tstrb, tstrb_from_master : std_logic_vector(keep_strb_length(slave_axi_stream)-1 downto 0);
8082
signal tid : std_logic_vector(id_length(slave_axi_stream)-1 downto 0);
8183
signal tdest : std_logic_vector(dest_length(slave_axi_stream)-1 downto 0);
8284
signal tuser : std_logic_vector(user_length(slave_axi_stream)-1 downto 0);
@@ -447,15 +449,21 @@ begin
447449
check_axi_stream(net, slave_axi_stream, not data, tlast => '0', tkeep => not keep, tstrb => not strb, tid => id, tdest => dest,
448450
tuser => user, msg => "checking axi stream");
449451

450-
check_log(mocklogger, "TDATA mismatch, checking axi stream - Got " &
451-
to_nibble_string(data) & " (" & to_string(to_integer(data)) & "). Expected " &
452-
to_nibble_string(not data) & " (" & to_string(to_integer(not data)) & ").", error);
453-
check_log(mocklogger, "TKEEP mismatch, checking axi stream - Got " &
454-
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
455-
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
456-
check_log(mocklogger, "TSTRB mismatch, checking axi stream - Got " &
457-
to_nibble_string(strb) & " (" & to_string(to_integer(strb)) & "). Expected " &
458-
to_nibble_string(not strb) & " (" & to_string(to_integer(not strb)) & ").", error);
452+
if data'length > 0 then
453+
check_log(mocklogger, "TDATA mismatch, checking axi stream - Got " &
454+
to_nibble_string(data) & " (" & to_string(to_integer(data)) & "). Expected " &
455+
to_nibble_string(not data) & " (" & to_string(to_integer(not data)) & ").", error);
456+
end if;
457+
if tkeep'length > 0 then
458+
check_log(mocklogger, "TKEEP mismatch, checking axi stream - Got " &
459+
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
460+
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
461+
end if;
462+
if tstrb'length > 0 then
463+
check_log(mocklogger, "TSTRB mismatch, checking axi stream - Got " &
464+
to_nibble_string(strb) & " (" & to_string(to_integer(strb)) & "). Expected " &
465+
to_nibble_string(not strb) & " (" & to_string(to_integer(not strb)) & ").", error);
466+
end if;
459467
check_log(mocklogger, "TLAST mismatch, checking axi stream - Got 1. Expected 0.", error);
460468
if id'length > 0 then
461469
check_log(mocklogger, "TID mismatch, checking axi stream - Got 0010_0010 (34). Expected 0010_0011 (35).", error);
@@ -586,16 +594,22 @@ begin
586594

587595
wait until rising_edge(aclk) and tvalid = '1';
588596
wait for 1 ps;
589-
590-
check_log(mocklogger, "TDATA mismatch, check non-blocking - Got " &
591-
to_nibble_string(data) & " (" & to_string(to_integer(data)) & "). Expected " &
592-
to_nibble_string(not data) & " (" & to_string(to_integer(not data)) & ").", error);
593-
check_log(mocklogger, "TKEEP mismatch, check non-blocking - Got " &
594-
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
595-
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
596-
check_log(mocklogger, "TSTRB mismatch, check non-blocking - Got " &
597-
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
598-
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
597+
598+
if data'length > 0 then
599+
check_log(mocklogger, "TDATA mismatch, check non-blocking - Got " &
600+
to_nibble_string(data) & " (" & to_string(to_integer(data)) & "). Expected " &
601+
to_nibble_string(not data) & " (" & to_string(to_integer(not data)) & ").", error);
602+
end if;
603+
if tkeep'length > 0 then
604+
check_log(mocklogger, "TKEEP mismatch, check non-blocking - Got " &
605+
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
606+
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
607+
end if;
608+
if tstrb'length > 0 then
609+
check_log(mocklogger, "TSTRB mismatch, check non-blocking - Got " &
610+
to_nibble_string(strb) & " (" & to_string(to_integer(strb)) & "). Expected " &
611+
to_nibble_string(not strb) & " (" & to_string(to_integer(not strb)) & ").", error);
612+
end if;
599613
check_log(mocklogger, "TLAST mismatch, check non-blocking - Got 1. Expected 0.", error);
600614
if id'length > 0 then
601615
check_log(mocklogger, "TID mismatch, check non-blocking - Got 0010_1010 (42). Expected 0010_1100 (44).", error);
@@ -685,7 +699,7 @@ begin
685699
tkeep <= tkeep_from_master when connected_tkeep else (others => '1');
686700
tstrb <= tstrb_from_master when connected_tstrb else (others => 'U');
687701

688-
not_valid <= not tvalid;
702+
not_valid <= not tvalid when g_data_length > 0 else '0';
689703

690704
not_valid_data <= '1' when is_x(tdata) else '0';
691705
check_true(aclk, not_valid, not_valid_data, "Invalid data not X");

vunit/vhdl/verification_components/test/tb_axi_stream_protocol_checker.vhd

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ architecture a of tb_axi_stream_protocol_checker is
3535
signal tlast : std_logic := '1';
3636
signal tdest : std_logic_vector(dest_length - 1 downto 0) := (others => '0');
3737
signal tid : std_logic_vector(id_length - 1 downto 0) := (others => '0');
38-
signal tstrb : std_logic_vector(data_length/8 - 1 downto 0) := (others => '0');
39-
signal tkeep : std_logic_vector(data_length/8 - 1 downto 0) := (others => '0');
38+
signal tstrb : std_logic_vector((data_length + 7) / 8 - 1 downto 0) := (others => '0');
39+
signal tkeep : std_logic_vector((data_length + 7) / 8 - 1 downto 0) := (others => '0');
4040
signal tuser : std_logic_vector(user_length - 1 downto 0) := (others => '0');
4141

4242
constant logger : logger_t := get_logger("protocol_checker");
4343
constant protocol_checker : axi_stream_protocol_checker_t := new_axi_stream_protocol_checker(
4444
data_length => tdata'length, id_length => tid'length, dest_length => tdest'length, user_length => tuser'length,
45-
logger => logger, actor => new_actor("protocol_checker"), max_waits => max_waits, allow_x_in_non_data_bytes => true
45+
logger => logger, actor => new_actor("protocol_checker"), max_waits => max_waits, allow_x_in_non_data_bytes => true,
46+
allow_arbitrary_data_length => data_length mod 8 /= 0
4647
);
4748
constant meta_values : std_logic_vector(1 to 5) := "-XWZU";
4849
constant valid_values : std_logic_vector(1 to 4) := "01LH";

0 commit comments

Comments
 (0)