Skip to content

Commit ef1d806

Browse files
committed
Add tkeep and tstrb support for non-byte tdata widths in AXI stream VCs.
The AXI standard is limited to byte-oriented data buses and specifies the width of tkeep and tstrb as tdata'length / 8. To support the use of non-byte tdata widths with active use of tkeep and tstrb, this has been changed to (tdata'length + 7) / 8 such that all bits in tdata are covered by a bit in tkeep and tstrb.
1 parent 4e30fa1 commit ef1d806

File tree

9 files changed

+92
-43
lines changed

9 files changed

+92
-43
lines changed

docs/news.d/1127.breaking.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
The AXI stream standard requires tdata to be a multiple of 8 bits. VUnit VCs allowed non-standard widths but the tkeep and tstrb
2+
signals didn't cover the most significant bits beyond the last full byte. For example, if the tdata width was 12 bits, tkeep and tstrb
3+
were one bit corresponding to the least significant byte in tdata. The 4 most significant bits didn't have a corresponding tkeep
4+
bit.
5+
6+
Starting in VUnit v5.0.0-dev2, the check features for AXI stream were updated such that comparison of the actual tdata value with the
7+
expected one, only considers bytes for which tkeep and tstrb are set. As a consequence, the upper bits of non-standard width tdata,
8+
for which there is no tkeep and tstrb bits, were not considered for comparison.
9+
10+
The VCs have now been updated to extend tkeep and tstrb in these cases such that all bits in tdata are considered for comparison.
11+
Existing testbenches using non-standard widths *and* tkeep or tstrb will have to be updated as the ports are one bit wider.

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: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ package axi_stream_pkg is
207207
impure function data_length(slave : axi_stream_slave_t) return natural;
208208
impure function data_length(monitor : axi_stream_monitor_t) return natural;
209209
impure function data_length(protocol_checker : axi_stream_protocol_checker_t) return natural;
210+
impure function keep_strb_length(master : axi_stream_master_t) return natural;
211+
impure function keep_strb_length(slave : axi_stream_slave_t) return natural;
212+
impure function keep_strb_length(monitor : axi_stream_monitor_t) return natural;
213+
impure function keep_strb_length(protocol_checker : axi_stream_protocol_checker_t) return natural;
210214
impure function id_length(master : axi_stream_master_t) return natural;
211215
impure function id_length(slave : axi_stream_slave_t) return natural;
212216
impure function id_length(monitor : axi_stream_monitor_t) return natural;
@@ -516,6 +520,26 @@ package body axi_stream_pkg is
516520
return protocol_checker.p_data_length;
517521
end;
518522

523+
impure function keep_strb_length(master : axi_stream_master_t) return natural is
524+
begin
525+
return (master.p_data_length + 7) / 8 ;
526+
end;
527+
528+
impure function keep_strb_length(slave : axi_stream_slave_t) return natural is
529+
begin
530+
return (slave.p_data_length + 7) / 8;
531+
end;
532+
533+
impure function keep_strb_length(monitor : axi_stream_monitor_t) return natural is
534+
begin
535+
return (monitor.p_data_length + 7) / 8;
536+
end;
537+
538+
impure function keep_strb_length(protocol_checker : axi_stream_protocol_checker_t) return natural is
539+
begin
540+
return (protocol_checker.p_data_length + 7) / 8;
541+
end;
542+
519543
impure function id_length(master : axi_stream_master_t) return natural is
520544
begin
521545
return master.p_id_length;
@@ -609,8 +633,8 @@ package body axi_stream_pkg is
609633
) is
610634
variable msg : msg_t := new_msg(push_axi_stream_msg);
611635
variable normalized_data : std_logic_vector(data_length(axi_stream)-1 downto 0) := (others => '0');
612-
variable normalized_keep : std_logic_vector(data_length(axi_stream)/8-1 downto 0) := (others => '1');
613-
variable normalized_strb : std_logic_vector(data_length(axi_stream)/8-1 downto 0) := (others => '1');
636+
variable normalized_keep : std_logic_vector(keep_strb_length(axi_stream)-1 downto 0) := (others => '1');
637+
variable normalized_strb : std_logic_vector(keep_strb_length(axi_stream)-1 downto 0) := (others => '1');
614638
variable normalized_id : std_logic_vector(id_length(axi_stream)-1 downto 0) := (others => '0');
615639
variable normalized_dest : std_logic_vector(dest_length(axi_stream)-1 downto 0) := (others => '0');
616640
variable normalized_user : std_logic_vector(user_length(axi_stream)-1 downto 0) := (others => '0');
@@ -733,8 +757,8 @@ package body axi_stream_pkg is
733757
constant expected_normalized : std_logic_vector(expected'length - 1 downto 0) := expected;
734758
variable got_tdata : std_logic_vector(data_length(axi_stream)-1 downto 0);
735759
variable got_tlast : std_logic;
736-
variable got_tkeep : std_logic_vector(data_length(axi_stream)/8-1 downto 0);
737-
variable got_tstrb : std_logic_vector(data_length(axi_stream)/8-1 downto 0);
760+
variable got_tkeep : std_logic_vector(keep_strb_length(axi_stream)-1 downto 0);
761+
variable got_tstrb : std_logic_vector(keep_strb_length(axi_stream)-1 downto 0);
738762
variable got_tid : std_logic_vector(id_length(axi_stream)-1 downto 0);
739763
variable got_tdest : std_logic_vector(dest_length(axi_stream)-1 downto 0);
740764
variable got_tuser : std_logic_vector(user_length(axi_stream)-1 downto 0);
@@ -746,7 +770,8 @@ package body axi_stream_pkg is
746770
mismatch := false;
747771
for idx in got_tkeep'range loop
748772
if got_tkeep(idx) and got_tstrb(idx) then
749-
mismatch := got_tdata(8 * idx + 7 downto 8 * idx) /= expected_normalized(8 * idx + 7 downto 8 * idx);
773+
mismatch := got_tdata(minimum(8 * idx + 7, got_tdata'left) downto 8 * idx) /=
774+
expected_normalized(minimum(8 * idx + 7, got_tdata'left) downto 8 * idx);
750775
exit when mismatch;
751776
end if;
752777
end loop;

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: 34 additions & 22 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;
@@ -75,8 +75,8 @@ architecture a of tb_axi_stream is
7575
signal tready : std_logic;
7676
signal tdata : std_logic_vector(data_length(slave_axi_stream)-1 downto 0);
7777
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);
78+
signal tkeep, tkeep_from_master : std_logic_vector(keep_strb_length(slave_axi_stream)-1 downto 0);
79+
signal tstrb, tstrb_from_master : std_logic_vector(keep_strb_length(slave_axi_stream)-1 downto 0);
8080
signal tid : std_logic_vector(id_length(slave_axi_stream)-1 downto 0);
8181
signal tdest : std_logic_vector(dest_length(slave_axi_stream)-1 downto 0);
8282
signal tuser : std_logic_vector(user_length(slave_axi_stream)-1 downto 0);
@@ -447,15 +447,21 @@ begin
447447
check_axi_stream(net, slave_axi_stream, not data, tlast => '0', tkeep => not keep, tstrb => not strb, tid => id, tdest => dest,
448448
tuser => user, msg => "checking axi stream");
449449

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);
450+
if data'length > 0 then
451+
check_log(mocklogger, "TDATA mismatch, checking axi stream - Got " &
452+
to_nibble_string(data) & " (" & to_string(to_integer(data)) & "). Expected " &
453+
to_nibble_string(not data) & " (" & to_string(to_integer(not data)) & ").", error);
454+
end if;
455+
if tkeep'length > 0 then
456+
check_log(mocklogger, "TKEEP mismatch, checking axi stream - Got " &
457+
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
458+
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
459+
end if;
460+
if tstrb'length > 0 then
461+
check_log(mocklogger, "TSTRB mismatch, checking axi stream - Got " &
462+
to_nibble_string(strb) & " (" & to_string(to_integer(strb)) & "). Expected " &
463+
to_nibble_string(not strb) & " (" & to_string(to_integer(not strb)) & ").", error);
464+
end if;
459465
check_log(mocklogger, "TLAST mismatch, checking axi stream - Got 1. Expected 0.", error);
460466
if id'length > 0 then
461467
check_log(mocklogger, "TID mismatch, checking axi stream - Got 0010_0010 (34). Expected 0010_0011 (35).", error);
@@ -587,15 +593,21 @@ begin
587593
wait until rising_edge(aclk) and tvalid = '1';
588594
wait for 1 ps;
589595

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);
596+
if data'length > 0 then
597+
check_log(mocklogger, "TDATA mismatch, check non-blocking - Got " &
598+
to_nibble_string(data) & " (" & to_string(to_integer(data)) & "). Expected " &
599+
to_nibble_string(not data) & " (" & to_string(to_integer(not data)) & ").", error);
600+
end if;
601+
if tkeep'length > 0 then
602+
check_log(mocklogger, "TKEEP mismatch, check non-blocking - Got " &
603+
to_nibble_string(keep) & " (" & to_string(to_integer(keep)) & "). Expected " &
604+
to_nibble_string(not keep) & " (" & to_string(to_integer(not keep)) & ").", error);
605+
end if;
606+
if tstrb'length > 0 then
607+
check_log(mocklogger, "TSTRB mismatch, check non-blocking - Got " &
608+
to_nibble_string(strb) & " (" & to_string(to_integer(strb)) & "). Expected " &
609+
to_nibble_string(not strb) & " (" & to_string(to_integer(not strb)) & ").", error);
610+
end if;
599611
check_log(mocklogger, "TLAST mismatch, check non-blocking - Got 1. Expected 0.", error);
600612
if id'length > 0 then
601613
check_log(mocklogger, "TID mismatch, check non-blocking - Got 0010_1010 (42). Expected 0010_1100 (44).", error);
@@ -685,7 +697,7 @@ begin
685697
tkeep <= tkeep_from_master when connected_tkeep else (others => '1');
686698
tstrb <= tstrb_from_master when connected_tstrb else (others => 'U');
687699

688-
not_valid <= not tvalid;
700+
not_valid <= not tvalid when g_data_length > 0 else '0';
689701

690702
not_valid_data <= '1' when is_x(tdata) else '0';
691703
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ 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");

0 commit comments

Comments
 (0)