diff --git a/vunit/vhdl/verification_components/run.py b/vunit/vhdl/verification_components/run.py index 4033e484f..8dee0b51e 100644 --- a/vunit/vhdl/verification_components/run.py +++ b/vunit/vhdl/verification_components/run.py @@ -144,7 +144,7 @@ def gen_avalon_master_tests(obj, *args): TB_AXI_STREAM_PROTOCOL_CHECKER = LIB.test_bench("tb_axi_stream_protocol_checker") -for data_length in [0, 8]: +for data_length in [0, 8, 32]: for test in TB_AXI_STREAM_PROTOCOL_CHECKER.get_tests("*passing*tdata*"): test.add_config(name="data_length=%d" % data_length, generics=dict(data_length=data_length)) diff --git a/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd b/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd index 84c388cae..40c1557d0 100644 --- a/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd +++ b/vunit/vhdl/verification_components/src/axi_stream_pkg.vhd @@ -34,39 +34,42 @@ package axi_stream_pkg is type axi_stream_component_type_t is (null_component, default_component, custom_component); type axi_stream_protocol_checker_t is record - p_type : axi_stream_component_type_t; - p_actor : actor_t; - p_data_length : natural; - p_id_length : natural; - p_dest_length : natural; - p_user_length : natural; - p_logger : logger_t; - p_max_waits : natural; + p_type : axi_stream_component_type_t; + p_actor : actor_t; + p_data_length : natural; + p_id_length : natural; + p_dest_length : natural; + p_user_length : natural; + p_logger : logger_t; + p_max_waits : natural; + p_allow_x_in_non_data_bytes : boolean; end record; constant null_axi_stream_protocol_checker : axi_stream_protocol_checker_t := ( - p_type => null_component, - p_actor => null_actor, - p_data_length => 0, - p_id_length => 0, - p_dest_length => 0, - p_user_length => 0, - p_logger => null_logger, - p_max_waits => 0 + p_type => null_component, + p_actor => null_actor, + p_data_length => 0, + p_id_length => 0, + p_dest_length => 0, + p_user_length => 0, + p_logger => null_logger, + p_max_waits => 0, + p_allow_x_in_non_data_bytes => false ); -- The default protocol checker is used to specify that the checker -- configuration is defined by the parent component into which the checker is -- instantiated. constant default_axi_stream_protocol_checker : axi_stream_protocol_checker_t := ( - p_type => default_component, - p_actor => null_actor, - p_data_length => 0, - p_id_length => 0, - p_dest_length => 0, - p_user_length => 0, - p_logger => null_logger, - p_max_waits => 0 + p_type => default_component, + p_actor => null_actor, + p_data_length => 0, + p_id_length => 0, + p_dest_length => 0, + p_user_length => 0, + p_logger => null_logger, + p_max_waits => 0, + p_allow_x_in_non_data_bytes => false ); type axi_stream_monitor_t is record @@ -191,13 +194,14 @@ package axi_stream_pkg is ) return axi_stream_monitor_t; impure function new_axi_stream_protocol_checker( - data_length : natural; - id_length : natural := 0; - dest_length : natural := 0; - user_length : natural := 0; - logger : logger_t := axi_stream_logger; - actor : actor_t := null_actor; - max_waits : natural := 16 + data_length : natural; + id_length : natural := 0; + dest_length : natural := 0; + user_length : natural := 0; + logger : logger_t := axi_stream_logger; + actor : actor_t := null_actor; + max_waits : natural := 16; + allow_x_in_non_data_bytes : boolean := false ) return axi_stream_protocol_checker_t; impure function data_length(master : axi_stream_master_t) return natural; @@ -469,24 +473,26 @@ package body axi_stream_pkg is end; impure function new_axi_stream_protocol_checker( - data_length : natural; - id_length : natural := 0; - dest_length : natural := 0; - user_length : natural := 0; - logger : logger_t := axi_stream_logger; - actor : actor_t := null_actor; - max_waits : natural := 16 + data_length : natural; + id_length : natural := 0; + dest_length : natural := 0; + user_length : natural := 0; + logger : logger_t := axi_stream_logger; + actor : actor_t := null_actor; + max_waits : natural := 16; + allow_x_in_non_data_bytes : boolean := false ) return axi_stream_protocol_checker_t is begin return ( - p_type => custom_component, - p_actor => actor, - p_data_length => data_length, - p_id_length => id_length, - p_dest_length => dest_length, - p_user_length => user_length, - p_logger => logger, - p_max_waits => max_waits); + p_type => custom_component, + p_actor => actor, + p_data_length => data_length, + p_id_length => id_length, + p_dest_length => dest_length, + p_user_length => user_length, + p_logger => logger, + p_max_waits => max_waits, + p_allow_x_in_non_data_bytes => allow_x_in_non_data_bytes); end; impure function data_length(master : axi_stream_master_t) return natural is diff --git a/vunit/vhdl/verification_components/src/axi_stream_protocol_checker.vhd b/vunit/vhdl/verification_components/src/axi_stream_protocol_checker.vhd index 49b49c84e..3276af83c 100644 --- a/vunit/vhdl/verification_components/src/axi_stream_protocol_checker.vhd +++ b/vunit/vhdl/verification_components/src/axi_stream_protocol_checker.vhd @@ -69,6 +69,20 @@ architecture a of axi_stream_protocol_checker is signal areset_n_d : std_logic := '0'; signal areset_rose : std_logic; signal not_tvalid : std_logic; + + signal tdata_normalized : std_logic_vector(tdata'range); + + function normalize_tdata(data, strb, keep : std_logic_vector) return std_logic_vector is + variable ret : std_logic_vector(data'range); + begin + ret := data; + for i in keep'range loop + if keep(i) = '0' or strb(i) = '0' then + ret(i*8+7 downto i*8) := (others => '0'); + end if; + end loop; + return ret; + end function; begin handshake_is_not_x <= '1' when not is_x(tvalid) and not is_x(tready) else '0'; @@ -112,7 +126,8 @@ begin -- AXI4STREAM_ERRM_TDATA_X A value of X on TDATA is not permitted when TVALID -- is HIGH - check_not_unknown(rule5_checker, aclk, tvalid, tdata, result("for tdata when tvalid is high")); + tdata_normalized <= normalize_tdata(tdata, tstrb, tkeep) when protocol_checker.p_allow_x_in_non_data_bytes else tdata; + check_not_unknown(rule5_checker, aclk, tvalid, tdata_normalized, result("for tdata when tvalid is high")); -- AXI4STREAM_ERRM_TLAST_X A value of X on TLAST is not permitted when TVALID -- is HIGH diff --git a/vunit/vhdl/verification_components/test/tb_axi_stream_protocol_checker.vhd b/vunit/vhdl/verification_components/test/tb_axi_stream_protocol_checker.vhd index 092151b25..d2fcfaa1e 100644 --- a/vunit/vhdl/verification_components/test/tb_axi_stream_protocol_checker.vhd +++ b/vunit/vhdl/verification_components/test/tb_axi_stream_protocol_checker.vhd @@ -42,7 +42,7 @@ architecture a of tb_axi_stream_protocol_checker is constant logger : logger_t := get_logger("protocol_checker"); constant protocol_checker : axi_stream_protocol_checker_t := new_axi_stream_protocol_checker( data_length => tdata'length, id_length => tid'length, dest_length => tdest'length, user_length => tuser'length, - logger => logger, actor => new_actor("protocol_checker"), max_waits => max_waits + logger => logger, actor => new_actor("protocol_checker"), max_waits => max_waits, allow_x_in_non_data_bytes => true ); constant meta_values : std_logic_vector(1 to 5) := "-XWZU"; constant valid_values : std_logic_vector(1 to 4) := "01LH"; @@ -168,6 +168,35 @@ begin end loop; end; + procedure pass_masked_unknown_test( + signal d, k, s : out std_logic_vector; + signal e1, e2 : out std_logic) is + variable p : integer; + begin + wait until rising_edge(aclk); + e1 <= '1'; + e2 <= '1'; + + for i in valid_values'range loop + for j in 0 to data_length/8*2-1 loop + for l in meta_values'range loop + k <= (k'range => '1'); + s <= (s'range => '1'); + if j < data_length/8 then + k(j) <= '0'; + p := j; + else + p := j-data_length/8; + end if; + d <= (d'range => valid_values(i)); + s(p) <= '0'; + d(p*8+7 downto p*8) <= (others => meta_values(l)); + wait until rising_edge(aclk); + end loop; + end loop; + end loop; + end; + procedure fail_unknown_test( signal d: out std_logic_vector; signal e1, e2: out std_logic; @@ -315,7 +344,12 @@ begin elsif run("Test passing check of that tdata must not be unknown when tvalid is high") then pass_unknown_test(tdata, tvalid, tready); + elsif run("Test passing check of that valid tdata bytes must not be unknown when tvalid is high") then + pass_masked_unknown_test(tdata, tkeep, tstrb, tvalid, tready); + elsif run("Test failing check of that tdata must not be unknown when tvalid is high") then + tkeep <= (others => '1'); + tstrb <= (others => '1'); fail_unknown_test(tdata, tvalid, tready, ":rule 5", "tdata", "tvalid"); elsif run("Test passing check of that tlast must not be unknown when tvalid is high") then