From 0cb30829a06de2330abe0adb197e7241a7eef001 Mon Sep 17 00:00:00 2001 From: Lars Asplund Date: Thu, 17 Oct 2024 21:44:20 +0200 Subject: [PATCH 01/23] Added VC standard rules --- docs/verification_components/user_guide.rst | 93 +++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/docs/verification_components/user_guide.rst b/docs/verification_components/user_guide.rst index 6ba1b35d1..3f7b113e1 100644 --- a/docs/verification_components/user_guide.rst +++ b/docs/verification_components/user_guide.rst @@ -90,3 +90,96 @@ A VC typically has an associated package defining procedures for sending to and Each VC instance is associated with a handle that is created in the test bench and set as a generic on the VC instantiation. The handle is given as an argument to the procedure calls to direct messages to the specific VC instance. + + +VC and VCI Compliance Testing +============================= + +VUnit establishes a standard for VCs and VCIs, designed around a set of rules that promote flexibility, reusability, interoperability, +and future-proofing of VCs and VCIs. + +Rule 1 +------ + +The file containing a VC entity shall include only one entity, and the file containing a VCI package shall include only one package. + +**Rationale**: This simplifies compliance testing, as the VC/VCI can be referenced by file name. + +Rule 2 +------ + +The function used to create a new instance of a VC (the constructor) shall have a name starting with ``new_``. + +**Rationale**: This naming convention allows the compliance test to easily identify the constructor and evaluate it against other applicable rules. + +Rule 3 +------ + +A VC constructor shall include an ``id`` parameter, allowing the user to specify the VC's identity. + +**Rationale**: This provides users control over the namespace assigned to the VC. + +Rule 4 +------ + +The ``id`` parameter shall default to ``null_id``. If not overridden, the ``id`` shall follow the format ``::``, where +```` starts at 1 for the first instance of the VC and increments with each subsequent instance. + +**Rationale**: This structured format ensures clear identification while preventing name collisions when combining VCs from different providers. + +Rule 5 +------ + +All identity-supporting objects associated with the VC (such as loggers, actors, and events) shall be assigned an identity within the namespace +defined by the constructor’s ``id`` parameter. + +**Rationale**: This gives users control over these objects and allows for easy association of log messages with a specific VC instance. + +Rule 6 +------ + +All checkers used by the VC shall report to the VC’s loggers. + +**Rationale**: This ensures that error messages are clearly linked to a specific VC instance. + +Rule 7 +------ + +A VC constructor shall include an ``unexpected_msg_type_policy`` parameter, allowing users to define the action taken when the VC receives an unexpected message type. + +**Rationale**: A VC actor subscribing to another actor may receive irrelevant messages, while VCs addressed directly should only receive messages they can process. + +Rule 10 +------- + +A VC shall keep the ``test_runner_cleanup`` entry gate locked while it has unfinished work, and must unlock the gate at all other times. + +**Rationale**: This prevents premature termination of the testbench. + +Rule 11 +------- + +All fields in the handle returned by the constructor shall begin with the prefix ``p_``. + +**Rationale**: This emphasizes that all fields are private, which simplifies future updates without breaking backward compatibility. + +Rule 12 +------- + +The standard configuration, ``std_cfg_t``, consisting of the required parameters for the constructor, shall be accessible through the handle via a ``get_std_cfg`` call. + +**Rationale**: This enables reuse of common operations across multiple VCs. + +Rule 13 +------- + +A VC shall only have one generic. + +**Rationale**: Representing a VC with a single object simplifies code management. Since all handle fields are private, future updates are less likely to break backward compatibility. + +Rule 14 +------- + +All VCs shall support the sync interface. + +**Rationale**: Being able to verify whether a VC is idle and introduce delays between transactions is a common and useful feature for VC users. From 0e7eabe3fdeed4fc3ef6a476d25df0cee102a5b2 Mon Sep 17 00:00:00 2001 From: Lars Asplund Date: Sun, 27 Oct 2024 22:18:16 +0100 Subject: [PATCH 02/23] Added rule for locking --- docs/verification_components/user_guide.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/verification_components/user_guide.rst b/docs/verification_components/user_guide.rst index 3f7b113e1..879cec8e9 100644 --- a/docs/verification_components/user_guide.rst +++ b/docs/verification_components/user_guide.rst @@ -183,3 +183,10 @@ Rule 14 All VCs shall support the sync interface. **Rationale**: Being able to verify whether a VC is idle and introduce delays between transactions is a common and useful feature for VC users. + +Rule 15 +------- + +A VC shall keep the ``test_runner_cleanup`` phase entry gate locked while there are pending operations. + +**Rationale**: Locking the gate prevents the simulation from terminating prematurely. From 4dd66f091179cb4596e53caec3a17d76c0753a9c Mon Sep 17 00:00:00 2001 From: Lars Asplund Date: Sat, 2 Nov 2024 13:45:00 +0100 Subject: [PATCH 03/23] Various updates to the rules. --- docs/verification_components/user_guide.rst | 96 ++++++++++++--------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/docs/verification_components/user_guide.rst b/docs/verification_components/user_guide.rst index 879cec8e9..a09707437 100644 --- a/docs/verification_components/user_guide.rst +++ b/docs/verification_components/user_guide.rst @@ -95,98 +95,110 @@ The handle is given as an argument to the procedure calls to direct messages to VC and VCI Compliance Testing ============================= -VUnit establishes a standard for VCs and VCIs, designed around a set of rules that promote flexibility, reusability, interoperability, -and future-proofing of VCs and VCIs. +VUnit establishes a standard for VCs and VCIs, designed around a set of rules that promote flexibility, +reusability, interoperability, and future-proofing of VCs and VCIs. Rule 1 ------ -The file containing a VC entity shall include only one entity, and the file containing a VCI package shall include only one package. +The file containing the VC entity shall contain only that entity, and the file containing the VCI package shall +contain only that package. -**Rationale**: This simplifies compliance testing, as the VC/VCI can be referenced by file name. +**Rationale**: This structure simplifies compliance testing, as each VC or VCI can be directly referenced by its +file name. Rule 2 ------ -The function used to create a new instance of a VC (the constructor) shall have a name starting with ``new_``. +A VC shall have only **one** generic, the *handle*, and it shall be of a record type containing **private** fields. -**Rationale**: This naming convention allows the compliance test to easily identify the constructor and evaluate it against other applicable rules. +**Rationale**: Using a record allows future updates to add and/or remove fields in the record without breaking +backward compatibility. + +**Recommendation**: Mark the fields as private by using a naming convention and/or including comments. This minimizes +the risk of users accessing fields directly. Rule 3 ------ -A VC constructor shall include an ``id`` parameter, allowing the user to specify the VC's identity. +The VC handle shall be created by a function, the *constructor*, which shall have a name beginning with ``new``. -**Rationale**: This provides users control over the namespace assigned to the VC. +**Rationale**: Using a constructor removes the need for users to directly access the private fields of the handle +record. The naming convention also enables compliance tests to easily locate the constructor and verify it against +other applicable rules. Rule 4 ------ -The ``id`` parameter shall default to ``null_id``. If not overridden, the ``id`` shall follow the format ``::``, where -```` starts at 1 for the first instance of the VC and increments with each subsequent instance. +The VC constructor shall include an ``id`` parameter of type ``id_t`` to enable the user to specify the VC's identity. -**Rationale**: This structured format ensures clear identification while preventing name collisions when combining VCs from different providers. +**Rationale**: This gives users control over the namespace assigned to the VC. Rule 5 ------ -All identity-supporting objects associated with the VC (such as loggers, actors, and events) shall be assigned an identity within the namespace -defined by the constructor’s ``id`` parameter. +The ``id`` parameter shall default to ``null_id``. If not overridden, ``id`` shall be assigned a value on the format +``::``, where ```` starts at 1 for the first instance of the VC and increments with each +additional instance. -**Rationale**: This gives users control over these objects and allows for easy association of log messages with a specific VC instance. +**Rationale**: This format ensures clear identification while preventing naming collisions when VCs from different +providers are combined. Rule 6 ------ -All checkers used by the VC shall report to the VC’s loggers. +All identity-supporting objects associated with the VC (such as loggers, actors, and events) shall be assigned an +identity within the namespace defined by the constructor’s ``id`` parameter. -**Rationale**: This ensures that error messages are clearly linked to a specific VC instance. +**Rationale**: This gives users control over these objects and simplifies the association of log messages with a +specific VC instance. Rule 7 ------ -A VC constructor shall include an ``unexpected_msg_type_policy`` parameter, allowing users to define the action taken when the VC receives an unexpected message type. - -**Rationale**: A VC actor subscribing to another actor may receive irrelevant messages, while VCs addressed directly should only receive messages they can process. - -Rule 10 -------- +All logging performed by the VC, including indirect logging (such that error logs from checkers), shall use the +VUnit logging mechanism. -A VC shall keep the ``test_runner_cleanup`` entry gate locked while it has unfinished work, and must unlock the gate at all other times. +**Rationale**: Using a unified logging mechanism ensures consistency and compatibility across logging outputs +from different VCs. -**Rationale**: This prevents premature termination of the testbench. - -Rule 11 -------- +Rule 8 +------ -All fields in the handle returned by the constructor shall begin with the prefix ``p_``. +Communication with the VC shall be based on VUnit message passing, and the VC actor’s identity shall match the +``id`` parameter provided to the constructor. -**Rationale**: This emphasizes that all fields are private, which simplifies future updates without breaking backward compatibility. +**Rationale**: This ensures a consistent communication framework and enables the reuse of VCIs across multiple VCs. -Rule 12 -------- +Rule 9 +------ -The standard configuration, ``std_cfg_t``, consisting of the required parameters for the constructor, shall be accessible through the handle via a ``get_std_cfg`` call. +All VCs shall support the sync interface. -**Rationale**: This enables reuse of common operations across multiple VCs. +**Rationale**: The ability to verify if a VC is idle and to introduce delays between transactions are frequently +needed features for VC users. -Rule 13 +Rule 10 ------- -A VC shall only have one generic. +The VC constructor shall include an ``unexpected_msg_type_policy`` parameter, allowing users to specify the action +taken when the VC receives an unexpected message type. -**Rationale**: Representing a VC with a single object simplifies code management. Since all handle fields are private, future updates are less likely to break backward compatibility. +**Rationale**: This policy enables flexibility in handling situations where a VC actor, subscribed to another actor, +might receive unsupported messages, while VCs addressed directly should only receive supported messages. -Rule 14 +Rule 11 ------- -All VCs shall support the sync interface. +The standard configuration (of type ``std_cfg_t``), which includes the required parameters for the constructor, shall +be accessible by calling ``get_std_cfg`` with the VC handle. -**Rationale**: Being able to verify whether a VC is idle and introduce delays between transactions is a common and useful feature for VC users. +**Rationale**: This enables reuse of common functions across multiple VCs. -Rule 15 +Rule 12 ------- -A VC shall keep the ``test_runner_cleanup`` phase entry gate locked while there are pending operations. +A VC shall keep the ``test_runner_cleanup`` phase entry gate locked as long as there are pending operations. -**Rationale**: Locking the gate prevents the simulation from terminating prematurely. +**Rationale**: Locking the gate ensures that the simulation does not terminate prematurely before all operations have +completed. From d3bf5414123c8ad970784bec76d0f8472c6447c0 Mon Sep 17 00:00:00 2001 From: Lars Asplund Date: Sun, 3 Nov 2024 17:23:17 +0100 Subject: [PATCH 04/23] Add support package for VCs. --- .../verification_components/src/vc_pkg.vhd | 143 ++++++++++++++++++ .../test/tb_vc_pkg.vhd | 102 +++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 vunit/vhdl/verification_components/src/vc_pkg.vhd create mode 100644 vunit/vhdl/verification_components/test/tb_vc_pkg.vhd diff --git a/vunit/vhdl/verification_components/src/vc_pkg.vhd b/vunit/vhdl/verification_components/src/vc_pkg.vhd new file mode 100644 index 000000000..00d7a5023 --- /dev/null +++ b/vunit/vhdl/verification_components/src/vc_pkg.vhd @@ -0,0 +1,143 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com +-- +-- This package contains common functionality for VCs. + +context work.vunit_context; +context work.com_context; + +package vc_pkg is + type unexpected_msg_type_policy_t is (fail, ignore); + + type std_cfg_t is record + p_id : id_t; + p_actor : actor_t; + p_logger : logger_t; + p_checker : checker_t; + p_unexpected_msg_type_policy : unexpected_msg_type_policy_t; + end record; + + constant null_std_cfg : std_cfg_t := ( + p_id => null_id, + p_actor => null_actor, + p_logger => null_logger, + p_checker => null_checker, + p_unexpected_msg_type_policy => ignore + ); + + -- Creates a standard VC configuration with an id, an actor, a logger, a + -- checker, and an unexpected message type policy. + -- + -- If id = null_id, the id will be assigned the name provider:vc_name:n where n is 1 + -- for the first instance and increasing with one for every additional instance. + -- + -- The id must not have an associated actor before the call as that may indicate + -- several users of the same actor. + -- + -- If a logger exist for the id, it will be reused. If not, a new logger is created. + -- A new checker is created that reports to the logger. + impure function create_std_cfg( + id : id_t := null_id; + provider : string := ""; + vc_name : string := ""; + unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail + ) return std_cfg_t; + + -- These functions extracts information from the standard VC configuration + impure function get_id(std_cfg : std_cfg_t) return id_t; + impure function get_actor(std_cfg : std_cfg_t) return actor_t; + impure function get_logger(std_cfg : std_cfg_t) return logger_t; + impure function get_checker(std_cfg : std_cfg_t) return checker_t; + impure function unexpected_msg_type_policy(std_cfg : std_cfg_t) return unexpected_msg_type_policy_t; + + -- Handle messages with unexpected message type according to the standard configuration + procedure unexpected_msg_type(msg_type : msg_type_t; std_cfg : std_cfg_t); + +end package; + +package body vc_pkg is + constant vc_pkg_logger : logger_t := get_logger("vunit_lib:vc_pkg"); + constant vc_pkg_checker : checker_t := new_checker(vc_pkg_logger); + + impure function create_std_cfg( + id : id_t := null_id; + provider : string := ""; + vc_name : string := ""; + unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail + ) return std_cfg_t is + variable result : std_cfg_t; + variable provider_id : id_t; + variable vc_id : id_t; + begin + if id /= null_id then + result.p_id := id; + else + if provider = "" then + check_failed(vc_pkg_checker, "A provider must be provided."); + + -- Simplifies testing when vc_pkg_checker logger is mocked + return null_std_cfg; + end if; + + if vc_name = "" then + check_failed(vc_pkg_checker, "A VC name must be provided."); + + -- Simplifies testing when vc_pkg_checker logger is mocked + return null_std_cfg; + end if; + + provider_id := get_id(provider); + vc_id := get_id(vc_name, parent => provider_id); + result.p_id := get_id(to_string(num_children(vc_id) + 1), parent => vc_id); + end if; + + result.p_unexpected_msg_type_policy := unexpected_msg_type_policy; + + if find(result.p_id, enable_deferred_creation => false) /= null_actor then + check_failed(vc_pkg_checker, "An actor already exists for " & full_name(result.p_id) & "."); + else + result.p_actor := new_actor(result.p_id); + end if; + + result.p_logger := get_logger(result.p_id); + result.p_checker := new_checker(result.p_logger); + + return result; + end; + + impure function get_id(std_cfg : std_cfg_t) return id_t is + begin + return std_cfg.p_id; + end; + + impure function get_actor(std_cfg : std_cfg_t) return actor_t is + begin + return std_cfg.p_actor; + end; + + impure function get_logger(std_cfg : std_cfg_t) return logger_t is + begin + return std_cfg.p_logger; + end; + + impure function get_checker(std_cfg : std_cfg_t) return checker_t is + begin + return std_cfg.p_checker; + end; + + impure function unexpected_msg_type_policy(std_cfg : std_cfg_t) return unexpected_msg_type_policy_t is + begin + return std_cfg.p_unexpected_msg_type_policy; + end; + + procedure unexpected_msg_type(msg_type : msg_type_t; + std_cfg : std_cfg_t) is + begin + if unexpected_msg_type_policy(std_cfg) = fail then + unexpected_msg_type(msg_type, get_logger(std_cfg)); + end if; + end; +end package body; diff --git a/vunit/vhdl/verification_components/test/tb_vc_pkg.vhd b/vunit/vhdl/verification_components/test/tb_vc_pkg.vhd new file mode 100644 index 000000000..805420e26 --- /dev/null +++ b/vunit/vhdl/verification_components/test/tb_vc_pkg.vhd @@ -0,0 +1,102 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library vunit_lib; +context vunit_lib.vunit_context; +context work.com_context; +use work.vc_pkg.all; + +entity tb_vc_pkg is + generic(runner_cfg : string); +end entity; + +architecture a of tb_vc_pkg is +begin + + main : process + variable std_cfg : std_cfg_t; + variable id : id_t; + variable actor : actor_t; + + constant vc_pkg_logger : logger_t := get_logger("vunit_lib:vc_pkg"); + constant unknown_msg_type : msg_type_t := new_msg_type("unknown_msg"); + begin + test_runner_setup(runner, runner_cfg); + while test_suite loop + if run("Test that provider must be supplied with null_id") then + mock(vc_pkg_logger, error); + std_cfg := create_std_cfg(vc_name => "my_vc"); + check_only_log(vc_pkg_logger, "A provider must be provided.", error); + unmock(vc_pkg_logger); + + elsif run("Test that vc_name must be supplied with null_id") then + mock(vc_pkg_logger, error); + std_cfg := create_std_cfg(provider => "provider"); + check_only_log(vc_pkg_logger, "A VC name must be provided.", error); + unmock(vc_pkg_logger); + + elsif run("Test standard config with specified id") then + id := get_id("id"); + std_cfg := create_std_cfg(id => id); + check(std_cfg.p_id = id); + check(std_cfg.p_actor = find(id, enable_deferred_creation => false)); + check(std_cfg.p_logger = get_logger(id)); + check(get_logger(std_cfg.p_checker) = get_logger(id)); + check(std_cfg.p_unexpected_msg_type_policy = fail); + + elsif run("Test standard config with null_id") then + for instance in 1 to 3 loop + std_cfg := create_std_cfg(provider => "provider", vc_name => "vc_name"); + id := std_cfg.p_id; + check(id = get_id("provider:vc_name:" & to_string(instance))); + check(std_cfg.p_actor = find(id, enable_deferred_creation => false)); + check(std_cfg.p_logger = get_logger(id)); + check(get_logger(std_cfg.p_checker) = get_logger(id)); + check(std_cfg.p_unexpected_msg_type_policy = fail); + end loop; + + elsif run("Test standard config with specified unexpected message type policy") then + std_cfg := create_std_cfg( + provider => "provider", + vc_name => "vc_name", + unexpected_msg_type_policy => ignore + ); + id := std_cfg.p_id; + check(id = get_id("provider:vc_name:1")); + check(std_cfg.p_actor = find(id, enable_deferred_creation => false)); + check(std_cfg.p_logger = get_logger(id)); + check(get_logger(std_cfg.p_checker) = get_logger(id)); + check(std_cfg.p_unexpected_msg_type_policy = ignore); + + elsif run("Test failing on reused actor") then + mock(vc_pkg_logger, error); + id := get_id("foo:bar"); + actor := new_actor(id); + std_cfg := create_std_cfg(id => id); + check_only_log(vc_pkg_logger, "An actor already exists for foo:bar.", error); + unmock(vc_pkg_logger); + + elsif run("Test failing on unexpected message") then + id := get_id("id"); + std_cfg := create_std_cfg(id => id); + mock(get_logger(id), failure); + unexpected_msg_type(unknown_msg_type, std_cfg); + check_only_log(get_logger(id), "Got unexpected message unknown_msg", failure); + unmock(get_logger(id)); + + elsif run("Test ignoring unexpected message") then + id := get_id("id"); + std_cfg := create_std_cfg(id => id, unexpected_msg_type_policy => ignore); + mock(get_logger(id), failure); + unexpected_msg_type(unknown_msg_type, std_cfg); + check_no_log; + unmock(get_logger(id)); + + end if; + end loop; + test_runner_cleanup(runner, fail_on_warning => true); + end process; +end architecture; From 4448cb5c9dc9420b08ab72b3bb9852a467f5a940 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 25 Oct 2024 00:38:39 +0200 Subject: [PATCH 05/23] initial checkin of APB master and slave VC --- .../src/apb_master.vhd | 147 ++++++++++++++++++ .../verification_components/src/apb_pkg.vhd | 53 +++++++ .../verification_components/src/apb_slave.vhd | 77 +++++++++ .../test/tb_apb_master.vhd | 138 ++++++++++++++++ 4 files changed, 415 insertions(+) create mode 100644 vunit/vhdl/verification_components/src/apb_master.vhd create mode 100644 vunit/vhdl/verification_components/src/apb_pkg.vhd create mode 100644 vunit/vhdl/verification_components/src/apb_slave.vhd create mode 100644 vunit/vhdl/verification_components/test/tb_apb_master.vhd diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_master.vhd new file mode 100644 index 000000000..cdd22ff77 --- /dev/null +++ b/vunit/vhdl/verification_components/src/apb_master.vhd @@ -0,0 +1,147 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.bus_master_pkg.all; +use work.check_pkg.all; +use work.com_pkg.all; +use work.com_types_pkg.all; +use work.queue_pkg.all; +use work.sync_pkg.all; +use work.logger_pkg.all; +use work.log_levels_pkg.all; + +entity apb_master is + generic ( + bus_handle : bus_master_t; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X' + ); + port ( + clk : in std_logic; + reset : in std_logic; + psel_o : out std_logic; + penable_o : out std_logic; + paddr_o : out std_logic_vector(address_length(bus_handle) - 1 downto 0); + pwrite_o : out std_logic; + pwdata_o : out std_logic_vector(data_length(bus_handle) - 1 downto 0); + prdata_i : in std_logic_vector(data_length(bus_handle) - 1 downto 0); + pready_i : in std_logic + ); +end entity; + +architecture behav of apb_master is + constant message_queue : queue_t := new_queue; + signal idle_bus : boolean := true; + + impure function queues_empty return boolean is + begin + return is_empty(message_queue); + end function; + + impure function is_idle return boolean is + begin + return idle_bus; + end function; + +begin + + PROC_MAIN: process + variable request_msg : msg_t; + variable msg_type : msg_type_t; + begin + DISPATCH_LOOP : loop + receive(net, bus_handle.p_actor, request_msg); + msg_type := message_type(request_msg); + + if msg_type = bus_read_msg then + push(message_queue, request_msg); + elsif msg_type = bus_write_msg then + push(message_queue, request_msg); + elsif msg_type = wait_until_idle_msg then + if not is_idle or not queues_empty then + wait until is_idle and queues_empty and rising_edge(clk); + end if; + handle_wait_until_idle(net, msg_type, request_msg); + else + unexpected_msg_type(msg_type); + end if; + end loop; + end process; + + BUS_PROCESS: process + procedure drive_bus_invalid is + begin + if drive_invalid then + penable_o <= drive_invalid_val; + paddr_o <= (paddr_o'range => drive_invalid_val); + pwrite_o <= drive_invalid_val; + pwdata_o <= (pwdata_o'range => drive_invalid_val); + end if; + end procedure; + + variable request_msg, reply_msg : msg_t; + variable msg_type : msg_type_t; + variable addr_this_transaction : std_logic_vector(paddr_o'range) := (others => '0'); + variable data_this_transaction : std_logic_vector(prdata_i'range) := (others => '0'); + begin + loop + drive_bus_invalid; + psel_o <= '0'; + + if is_empty(message_queue) then + wait until rising_edge(clk) and not is_empty(message_queue); + end if; + idle_bus <= false; + wait for 0 ns; + + request_msg := pop(message_queue); + msg_type := message_type(request_msg); + + if msg_type = bus_write_msg then + addr_this_transaction := pop_std_ulogic_vector(request_msg); + data_this_transaction := pop_std_ulogic_vector(request_msg); + + psel_o <= '1'; + penable_o <= '0'; + pwrite_o <= '1'; + paddr_o <= addr_this_transaction; + pwdata_o <= data_this_transaction; + + wait until rising_edge(clk); + penable_o <= '1'; + wait until (pready_i and penable_o) = '1' and rising_edge(clk); + + if is_visible(bus_handle.p_logger, debug) then + debug(bus_handle.p_logger, + "Wrote 0x" & to_hstring(data_this_transaction) & + " to address 0x" & to_hstring(addr_this_transaction)); + end if; + + elsif msg_type = bus_read_msg then + addr_this_transaction := pop_std_ulogic_vector(request_msg); + + psel_o <= '1'; + penable_o <= '0'; + pwrite_o <= '0'; + paddr_o <= addr_this_transaction; + + wait until rising_edge(clk); + penable_o <= '1'; + wait until (pready_i and penable_o) = '1' and rising_edge(clk); + + reply_msg := new_msg; + push_std_ulogic_vector(reply_msg, prdata_i); + reply(net, request_msg, reply_msg); + end if; + + idle_bus <= true; + end loop; + end process; +end architecture; diff --git a/vunit/vhdl/verification_components/src/apb_pkg.vhd b/vunit/vhdl/verification_components/src/apb_pkg.vhd new file mode 100644 index 000000000..e9fa4fc12 --- /dev/null +++ b/vunit/vhdl/verification_components/src/apb_pkg.vhd @@ -0,0 +1,53 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.com_pkg.all; +use work.com_types_pkg.all; +use work.logger_pkg.all; +use work.memory_pkg.memory_t; +use work.memory_pkg.to_vc_interface; + +package apb_pkg is + + type apb_slave_t is record + ready_high_probability : real range 0.0 to 1.0; + -- Private + p_actor : actor_t; + p_memory : memory_t; + p_logger : logger_t; + end record; + + constant apb_slave_logger : logger_t := get_logger("vunit_lib:apb_slave_pkg"); + impure function new_apb_slave( + memory : memory_t; + ready_high_probability : real := 1.0; + logger : logger_t := apb_slave_logger) + return apb_slave_t; + + constant slave_write_msg : msg_type_t := new_msg_type("apb slave write"); + constant slave_read_msg : msg_type_t := new_msg_type("apb slave read"); +end package; + +package body apb_pkg is + + impure function new_apb_slave( + memory : memory_t; + ready_high_probability : real := 1.0; + logger : logger_t := apb_slave_logger) + return apb_slave_t is + begin + return (p_actor => new_actor, + p_memory => to_vc_interface(memory, logger), + p_logger => logger, + ready_high_probability => ready_high_probability + ); + end; + +end package body; \ No newline at end of file diff --git a/vunit/vhdl/verification_components/src/apb_slave.vhd b/vunit/vhdl/verification_components/src/apb_slave.vhd new file mode 100644 index 000000000..7f698ec61 --- /dev/null +++ b/vunit/vhdl/verification_components/src/apb_slave.vhd @@ -0,0 +1,77 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.memory_pkg.all; +use work.apb_pkg.all; +use work.logger_pkg.all; + +entity apb_slave is + generic ( + bus_handle : apb_slave_t; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X' + ); + port ( + clk : in std_logic; + reset : in std_logic; + psel_i : in std_logic; + penable_i : in std_logic; + paddr_i : in std_logic_vector; + pwrite_i : in std_logic; + pwdata_i : in std_logic_vector; + prdata_o : out std_logic_vector; + pready_o : out std_logic + ); +end entity; + +architecture a of apb_slave is + +begin + + PROC_MAIN: process + procedure drive_outputs_invalid is + begin + if drive_invalid then + prdata_o <= (prdata_o'range => drive_invalid_val); + pready_o <= drive_invalid_val; + end if; + end procedure; + + variable addr : integer; + begin + drive_outputs_invalid; + wait until rising_edge(clk); + + loop + -- IDLE/SETUP state + drive_outputs_invalid; + + wait until psel_i = '1' and rising_edge(clk); + -- ACCESS state + + pready_o <= '1'; + + addr := to_integer(unsigned(paddr_i)); + + if pwrite_i = '1' then + write_word(bus_handle.p_memory, addr, pwdata_i); + else + prdata_o <= read_word(bus_handle.p_memory, addr, prdata_o'length/8); + end if; + + wait until rising_edge(clk); + + if penable_i = '0' then + failure(bus_handle.p_logger, "penable_i must be active in the ACCESS phase."); + end if; + end loop; + end process; + +end architecture; \ No newline at end of file diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd new file mode 100644 index 000000000..be8437b51 --- /dev/null +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -0,0 +1,138 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +context work.vunit_context; +context work.com_context; +use work.memory_pkg.all; +use work.bus_master_pkg.all; +use work.apb_pkg.all; +use work.logger_pkg.all; + +library osvvm; +use osvvm.RandomPkg.all; + +entity tb_apb_master is + generic ( + runner_cfg : string + ); +end entity; + +architecture a of tb_apb_master is + + constant BUS_DATA_WIDTH : natural := 16; + constant BUS_ADDRESS_WIDTH : natural := 32; + + signal clk : std_logic := '0'; + signal reset : std_logic := '0'; + signal psel : std_logic; + signal penable : std_logic; + signal paddr : std_logic_vector(BUS_ADDRESS_WIDTH-1 downto 0); + signal pwrite : std_logic; + signal pwdata : std_logic_vector(BUS_DATA_WIDTH-1 downto 0); + signal prdata : std_logic_vector(BUS_DATA_WIDTH-1 downto 0); + signal pready : std_logic := '0'; + + constant bus_handle : bus_master_t := new_bus(data_length => pwdata'length, + address_length => paddr'length); + constant memory : memory_t := new_memory; + constant slave_handle : apb_slave_t := new_apb_slave(memory => memory, + logger => get_logger("apb slave")); + + signal start : boolean := false; +begin + + main_stim : process + variable buf : buffer_t; + variable data : std_logic_vector(prdata'range); + variable bus_ref1, bus_ref2 : bus_reference_t; + begin + show(get_logger("apb slave"), display_handler, debug); + + test_runner_setup(runner, runner_cfg); + start <= true; + wait for 0 ns; + + if run("single_write") then + buf := allocate(memory => memory, num_bytes => 2, permissions => write_only); + mock(get_logger(bus_handle), debug); + write_bus(net, bus_handle, base_address(buf), x"1122"); + wait_until_idle(net, bus_handle); + check_only_log(get_logger(bus_handle), "Wrote 0x1122 to address 0x00000000", debug); + unmock(get_logger(bus_handle)); + + elsif run("single_read") then + buf := allocate(memory => memory, num_bytes => 2, permissions => read_only); + write_word(memory, base_address(buf), x"1234"); + read_bus(net, bus_handle, base_address(buf), data); + check_equal(data, std_logic_vector'(x"1234"), "Check read data."); + + elsif run("consecutive_reads") then + buf := allocate(memory => memory, num_bytes => 4, permissions => read_only); + write_word(memory, base_address(buf), x"1234"); + write_word(memory, base_address(buf)+2, x"5678"); + read_bus(net, bus_handle, base_address(buf), bus_ref1); + read_bus(net, bus_handle, base_address(buf)+2, bus_ref2); + await_read_bus_reply(net, bus_ref1, data); + check_equal(data, std_logic_vector'(x"1234"), "Check read data."); + await_read_bus_reply(net, bus_ref2, data); + check_equal(data, std_logic_vector'(x"5678"), "Check read data."); + + elsif run("consecutive_writes") then + buf := allocate(memory => memory, num_bytes => 4, permissions => write_only); + set_expected_word(memory, base_address(buf), x"1234"); + set_expected_word(memory, base_address(buf)+2, x"5678"); + write_bus(net, bus_handle, base_address(buf), x"1234"); + write_bus(net, bus_handle, base_address(buf)+2, x"5678"); + wait_until_idle(net, bus_handle); + check_expected_was_written(memory); + + end if; + + wait for 100 ns; + + test_runner_cleanup(runner); + wait; + end process; + test_runner_watchdog(runner, 100 us); + + U_DUT_MASTER: entity work.apb_master + generic map ( + bus_handle => bus_handle + ) + port map ( + clk => clk, + reset => reset, + psel_o => psel, + penable_o => penable, + paddr_o => paddr, + pwrite_o => pwrite, + pwdata_o => pwdata, + prdata_i => prdata, + pready_i => pready + ); + + U_DUT_SLAVE: entity work.apb_slave + generic map ( + bus_handle => slave_handle + ) + port map ( + clk => clk, + reset => reset, + psel_i => psel, + penable_i => penable, + paddr_i => paddr, + pwrite_i => pwrite, + pwdata_i => pwdata, + prdata_o => prdata, + pready_o => pready + ); + + clk <= not clk after 5 ns; +end architecture; From efb0849e869120013126b48355041206b0f8bb01 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 25 Oct 2024 00:48:38 +0200 Subject: [PATCH 06/23] set expected word for single write test --- vunit/vhdl/verification_components/test/tb_apb_master.vhd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd index be8437b51..59ca40ae5 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -62,10 +62,12 @@ begin if run("single_write") then buf := allocate(memory => memory, num_bytes => 2, permissions => write_only); mock(get_logger(bus_handle), debug); + set_expected_word(memory, base_address(buf), x"1122"); write_bus(net, bus_handle, base_address(buf), x"1122"); wait_until_idle(net, bus_handle); check_only_log(get_logger(bus_handle), "Wrote 0x1122 to address 0x00000000", debug); unmock(get_logger(bus_handle)); + check_expected_was_written(memory); elsif run("single_read") then buf := allocate(memory => memory, num_bytes => 2, permissions => read_only); From d15414ccde5565c00f368d3936a86f2b63dcbb9b Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 25 Oct 2024 02:07:01 +0200 Subject: [PATCH 07/23] implement wait states --- .../verification_components/src/apb_slave.vhd | 9 +++++++ .../test/tb_apb_master.vhd | 24 +++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_slave.vhd b/vunit/vhdl/verification_components/src/apb_slave.vhd index 7f698ec61..8c1bd615a 100644 --- a/vunit/vhdl/verification_components/src/apb_slave.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave.vhd @@ -8,6 +8,9 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +library osvvm; +use osvvm.RandomPkg.RandomPType; + use work.memory_pkg.all; use work.apb_pkg.all; use work.logger_pkg.all; @@ -45,6 +48,7 @@ begin end procedure; variable addr : integer; + variable rnd : RandomPType; begin drive_outputs_invalid; wait until rising_edge(clk); @@ -56,6 +60,11 @@ begin wait until psel_i = '1' and rising_edge(clk); -- ACCESS state + while rnd.Uniform(0.0, 1.0) > bus_handle.ready_high_probability loop + pready_o <= '0'; + wait until rising_edge(clk); + end loop; + pready_o <= '1'; addr := to_integer(unsigned(paddr_i)); diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd index 59ca40ae5..f2e24f55c 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -43,14 +43,15 @@ architecture a of tb_apb_master is address_length => paddr'length); constant memory : memory_t := new_memory; constant slave_handle : apb_slave_t := new_apb_slave(memory => memory, - logger => get_logger("apb slave")); + logger => get_logger("apb slave"), + ready_high_probability => 0.5); signal start : boolean := false; begin main_stim : process variable buf : buffer_t; - variable data : std_logic_vector(prdata'range); + variable data, data2 : std_logic_vector(prdata'range); variable bus_ref1, bus_ref2 : bus_reference_t; begin show(get_logger("apb slave"), display_handler, debug); @@ -95,6 +96,25 @@ begin wait_until_idle(net, bus_handle); check_expected_was_written(memory); + elsif run("many_reads") then + for i in 1 to 100 loop + buf := allocate(memory => memory, num_bytes => 2, permissions => read_only); + data := std_logic_vector(to_unsigned(i, BUS_DATA_WIDTH)); + write_word(memory, base_address(buf), data); + read_bus(net, bus_handle, base_address(buf), data2); + check_equal(data2, data, "Check read data."); + end loop; + + elsif run("many_writes") then + for i in 1 to 100 loop + buf := allocate(memory => memory, num_bytes => 2, permissions => write_only); + data := std_logic_vector(to_unsigned(i, BUS_DATA_WIDTH)); + set_expected_word(memory, base_address(buf), data); + write_bus(net, bus_handle, base_address(buf), data); + end loop; + wait_until_idle(net, bus_handle); + check_expected_was_written(memory); + end if; wait for 100 ns; From 60ce019dda31525c37c1e62d6b97d3e56012a897 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Mon, 28 Oct 2024 01:30:16 +0100 Subject: [PATCH 08/23] fix trailing whitespace --- vunit/vhdl/verification_components/test/tb_apb_master.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd index f2e24f55c..3bdc9a521 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -126,7 +126,7 @@ begin U_DUT_MASTER: entity work.apb_master generic map ( - bus_handle => bus_handle + bus_handle => bus_handle ) port map ( clk => clk, From 49f5c3cd9f00fd9a321d2f18634fa680c3885e3c Mon Sep 17 00:00:00 2001 From: c-thaler Date: Mon, 28 Oct 2024 01:32:30 +0100 Subject: [PATCH 09/23] fix another trailing whitespace --- vunit/vhdl/verification_components/src/apb_master.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_master.vhd index cdd22ff77..9c46ccf7e 100644 --- a/vunit/vhdl/verification_components/src/apb_master.vhd +++ b/vunit/vhdl/verification_components/src/apb_master.vhd @@ -49,7 +49,7 @@ architecture behav of apb_master is begin return idle_bus; end function; - + begin PROC_MAIN: process From 86cb9e8f18f9b5c12218c171e10f0b71c14168e6 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Tue, 29 Oct 2024 00:16:53 +0100 Subject: [PATCH 10/23] use single generic parameter All generics are now integrated into a single parameter of type apb_master_t. --- .../src/apb_master.vhd | 27 +- .../src/apb_master_pkg.vhd | 250 ++++++++++++++++++ .../verification_components/src/apb_slave.vhd | 2 +- .../src/{apb_pkg.vhd => apb_slave_pkg.vhd} | 4 +- .../test/tb_apb_master.vhd | 7 +- 5 files changed, 270 insertions(+), 20 deletions(-) create mode 100644 vunit/vhdl/verification_components/src/apb_master_pkg.vhd rename vunit/vhdl/verification_components/src/{apb_pkg.vhd => apb_slave_pkg.vhd} (96%) diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_master.vhd index 9c46ccf7e..70d3d7880 100644 --- a/vunit/vhdl/verification_components/src/apb_master.vhd +++ b/vunit/vhdl/verification_components/src/apb_master.vhd @@ -16,22 +16,21 @@ use work.queue_pkg.all; use work.sync_pkg.all; use work.logger_pkg.all; use work.log_levels_pkg.all; +use work.apb_master_pkg.all; entity apb_master is generic ( - bus_handle : bus_master_t; - drive_invalid : boolean := true; - drive_invalid_val : std_logic := 'X' + bus_handle : apb_master_t ); port ( clk : in std_logic; reset : in std_logic; psel_o : out std_logic; penable_o : out std_logic; - paddr_o : out std_logic_vector(address_length(bus_handle) - 1 downto 0); + paddr_o : out std_logic_vector(address_length(bus_handle.p_bus_handle) - 1 downto 0); pwrite_o : out std_logic; - pwdata_o : out std_logic_vector(data_length(bus_handle) - 1 downto 0); - prdata_i : in std_logic_vector(data_length(bus_handle) - 1 downto 0); + pwdata_o : out std_logic_vector(data_length(bus_handle.p_bus_handle) - 1 downto 0); + prdata_i : in std_logic_vector(data_length(bus_handle.p_bus_handle) - 1 downto 0); pready_i : in std_logic ); end entity; @@ -57,7 +56,7 @@ begin variable msg_type : msg_type_t; begin DISPATCH_LOOP : loop - receive(net, bus_handle.p_actor, request_msg); + receive(net, bus_handle.p_bus_handle.p_actor, request_msg); msg_type := message_type(request_msg); if msg_type = bus_read_msg then @@ -78,11 +77,11 @@ begin BUS_PROCESS: process procedure drive_bus_invalid is begin - if drive_invalid then - penable_o <= drive_invalid_val; - paddr_o <= (paddr_o'range => drive_invalid_val); - pwrite_o <= drive_invalid_val; - pwdata_o <= (pwdata_o'range => drive_invalid_val); + if bus_handle.p_drive_invalid then + penable_o <= bus_handle.p_drive_invalid_val; + paddr_o <= (paddr_o'range => bus_handle.p_drive_invalid_val); + pwrite_o <= bus_handle.p_drive_invalid_val; + pwdata_o <= (pwdata_o'range => bus_handle.p_drive_invalid_val); end if; end procedure; @@ -118,8 +117,8 @@ begin penable_o <= '1'; wait until (pready_i and penable_o) = '1' and rising_edge(clk); - if is_visible(bus_handle.p_logger, debug) then - debug(bus_handle.p_logger, + if is_visible(bus_handle.p_bus_handle.p_logger, debug) then + debug(bus_handle.p_bus_handle.p_logger, "Wrote 0x" & to_hstring(data_this_transaction) & " to address 0x" & to_hstring(addr_this_transaction)); end if; diff --git a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd new file mode 100644 index 000000000..f7bff7fd3 --- /dev/null +++ b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd @@ -0,0 +1,250 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2024, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.bus_master_pkg.all; +use work.com_pkg.all; +use work.com_types_pkg.all; +use work.logger_pkg.all; +use work.memory_pkg.memory_t; +use work.memory_pkg.to_vc_interface; + +package apb_master_pkg is + + type apb_master_t is record + -- Private + p_bus_handle : bus_master_t; + p_drive_invalid : boolean; + p_drive_invalid_val : std_logic; + p_ready_high_probability : real range 0.0 to 1.0; + end record; + + impure function new_apb_master( + data_length : natural; + address_length : natural; + logger : logger_t := bus_logger; + actor : actor_t := null_actor; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X'; + ready_high_probability : real := 1.0 + ) return apb_master_t; + + function get_logger(bus_handle : apb_master_t) return logger_t; + + -- Blocking: Write the bus + procedure write_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := ""); + procedure write_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + constant data : std_logic_vector; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := ""); + + procedure wait_until_idle(signal net : inout network_t; + bus_handle : apb_master_t); + + -- Non blocking: Read the bus returning a reference to the future reply + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + variable reference : inout bus_reference_t); + + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + variable reference : inout bus_reference_t); + + -- Blocking: read bus with immediate reply + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + variable data : inout std_logic_vector); + + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + variable data : inout std_logic_vector); + + -- Blocking: Read bus and check result against expected data + procedure check_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + constant expected : std_logic_vector; + constant msg : string := ""); + + procedure check_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + constant expected : std_logic_vector; + constant msg : string := ""); + + -- Blocking: Wait until a read from address equals the value using + -- std_match If timeout is reached error with msg + procedure wait_until_read_equals( + signal net : inout network_t; + bus_handle : apb_master_t; + addr : std_logic_vector; + value : std_logic_vector; + timeout : delay_length := delay_length'high; + msg : string := ""); + + -- Blocking: Wait until a read from address has the bit with this + -- index set to value If timeout is reached error with msg + procedure wait_until_read_bit_equals( + signal net : inout network_t; + bus_handle : apb_master_t; + addr : std_logic_vector; + idx : natural; + value : std_logic; + timeout : delay_length := delay_length'high; + msg : string := ""); +end package; + +package body apb_master_pkg is + + impure function new_apb_master( + data_length : natural; + address_length : natural; + logger : logger_t := bus_logger; + actor : actor_t := null_actor; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X'; + ready_high_probability : real := 1.0 + ) return apb_master_t is + variable bus_handle : bus_master_t := new_bus( + data_length => data_length, + address_length => address_length, + logger => logger, + actor => actor + ); + begin + return ( + p_bus_handle => bus_handle, + p_drive_invalid => drive_invalid, + p_drive_invalid_val => drive_invalid_val, + p_ready_high_probability => ready_high_probability + ); + end; + + function get_logger(bus_handle : apb_master_t) return logger_t is + begin + return get_logger(bus_handle.p_bus_handle); + end function; + + -- Blocking: Write the bus + procedure write_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + constant data : std_logic_vector; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := "") is + begin + write_bus(net, bus_handle.p_bus_handle, address, data, byte_enable); + end procedure; + + procedure write_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + constant data : std_logic_vector; + -- default byte enable is all bytes + constant byte_enable : std_logic_vector := "") is + begin + write_bus(net, bus_handle.p_bus_handle, address, data, byte_enable); + end procedure; + + procedure wait_until_idle(signal net : inout network_t; + bus_handle : apb_master_t) is + begin + wait_until_idle(net, bus_handle.P_bus_handle); + end procedure; + + -- Blocking: read bus with immediate reply + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + variable data : inout std_logic_vector) is + begin + read_bus(net, bus_handle.p_bus_handle, address, data); + end procedure; + + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + variable data : inout std_logic_vector) is + begin + read_bus(net, bus_handle.p_bus_handle, address, data); + end procedure; + + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + variable reference : inout bus_reference_t) is + begin + read_bus(net, bus_handle.p_bus_handle, address, reference); + end procedure; + + procedure read_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + variable reference : inout bus_reference_t) is + begin + read_bus(net, bus_handle.p_bus_handle, address, reference); + end procedure; + + -- Blocking: Read bus and check result against expected data + procedure check_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : std_logic_vector; + constant expected : std_logic_vector; + constant msg : string := "") is + begin + check_bus(net, bus_handle.p_bus_handle, address, expected, msg); + end procedure; + + procedure check_bus(signal net : inout network_t; + constant bus_handle : apb_master_t; + constant address : natural; + constant expected : std_logic_vector; + constant msg : string := "") is + begin + check_bus(net, bus_handle.p_bus_handle, address, expected, msg); + end procedure; + + -- Blocking: Wait until a read from address equals the value using + -- std_match If timeout is reached error with msg + procedure wait_until_read_equals( + signal net : inout network_t; + bus_handle : apb_master_t; + addr : std_logic_vector; + value : std_logic_vector; + timeout : delay_length := delay_length'high; + msg : string := "") is + begin + wait_until_read_equals(net, bus_handle.p_bus_handle, addr, value, timeout, msg); + end procedure; + + -- Blocking: Wait until a read from address has the bit with this + -- index set to value If timeout is reached error with msg + procedure wait_until_read_bit_equals( + signal net : inout network_t; + bus_handle : apb_master_t; + addr : std_logic_vector; + idx : natural; + value : std_logic; + timeout : delay_length := delay_length'high; + msg : string := "") is + begin + wait_until_read_bit_equals(net, bus_handle.p_bus_handle, addr, idx, value, timeout, msg); + end procedure; +end package body; \ No newline at end of file diff --git a/vunit/vhdl/verification_components/src/apb_slave.vhd b/vunit/vhdl/verification_components/src/apb_slave.vhd index 8c1bd615a..3dfba6885 100644 --- a/vunit/vhdl/verification_components/src/apb_slave.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave.vhd @@ -12,7 +12,7 @@ library osvvm; use osvvm.RandomPkg.RandomPType; use work.memory_pkg.all; -use work.apb_pkg.all; +use work.apb_slave_pkg.all; use work.logger_pkg.all; entity apb_slave is diff --git a/vunit/vhdl/verification_components/src/apb_pkg.vhd b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd similarity index 96% rename from vunit/vhdl/verification_components/src/apb_pkg.vhd rename to vunit/vhdl/verification_components/src/apb_slave_pkg.vhd index e9fa4fc12..c89a36945 100644 --- a/vunit/vhdl/verification_components/src/apb_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd @@ -14,7 +14,7 @@ use work.logger_pkg.all; use work.memory_pkg.memory_t; use work.memory_pkg.to_vc_interface; -package apb_pkg is +package apb_slave_pkg is type apb_slave_t is record ready_high_probability : real range 0.0 to 1.0; @@ -35,7 +35,7 @@ package apb_pkg is constant slave_read_msg : msg_type_t := new_msg_type("apb slave read"); end package; -package body apb_pkg is +package body apb_slave_pkg is impure function new_apb_slave( memory : memory_t; diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd index 3bdc9a521..719e96f30 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -12,7 +12,8 @@ context work.vunit_context; context work.com_context; use work.memory_pkg.all; use work.bus_master_pkg.all; -use work.apb_pkg.all; +use work.apb_slave_pkg.all; +use work.apb_master_pkg.all; use work.logger_pkg.all; library osvvm; @@ -39,8 +40,8 @@ architecture a of tb_apb_master is signal prdata : std_logic_vector(BUS_DATA_WIDTH-1 downto 0); signal pready : std_logic := '0'; - constant bus_handle : bus_master_t := new_bus(data_length => pwdata'length, - address_length => paddr'length); + constant bus_handle : apb_master_t := new_apb_master(data_length => pwdata'length, + address_length => paddr'length); constant memory : memory_t := new_memory; constant slave_handle : apb_slave_t := new_apb_slave(memory => memory, logger => get_logger("apb slave"), From a658da4702c19b531fc46e2e5f85f9aa4fc01eb1 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Tue, 29 Oct 2024 01:15:36 +0100 Subject: [PATCH 11/23] reduce to single generic parameter in apb slave --- .../verification_components/src/apb_slave.vhd | 12 +++---- .../src/apb_slave_pkg.vhd | 32 +++++++++++++------ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_slave.vhd b/vunit/vhdl/verification_components/src/apb_slave.vhd index 3dfba6885..b4b61a7a4 100644 --- a/vunit/vhdl/verification_components/src/apb_slave.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave.vhd @@ -17,9 +17,7 @@ use work.logger_pkg.all; entity apb_slave is generic ( - bus_handle : apb_slave_t; - drive_invalid : boolean := true; - drive_invalid_val : std_logic := 'X' + bus_handle : apb_slave_t ); port ( clk : in std_logic; @@ -41,9 +39,9 @@ begin PROC_MAIN: process procedure drive_outputs_invalid is begin - if drive_invalid then - prdata_o <= (prdata_o'range => drive_invalid_val); - pready_o <= drive_invalid_val; + if bus_handle.p_drive_invalid then + prdata_o <= (prdata_o'range => bus_handle.p_drive_invalid_val); + pready_o <= bus_handle.p_drive_invalid_val; end if; end procedure; @@ -60,7 +58,7 @@ begin wait until psel_i = '1' and rising_edge(clk); -- ACCESS state - while rnd.Uniform(0.0, 1.0) > bus_handle.ready_high_probability loop + while rnd.Uniform(0.0, 1.0) > bus_handle.p_ready_high_probability loop pready_o <= '0'; wait until rising_edge(clk); end loop; diff --git a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd index c89a36945..5e00046e4 100644 --- a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd @@ -8,6 +8,7 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use work.bus_master_pkg.all; use work.com_pkg.all; use work.com_types_pkg.all; use work.logger_pkg.all; @@ -17,18 +18,23 @@ use work.memory_pkg.to_vc_interface; package apb_slave_pkg is type apb_slave_t is record - ready_high_probability : real range 0.0 to 1.0; -- Private p_actor : actor_t; p_memory : memory_t; p_logger : logger_t; + p_drive_invalid : boolean; + p_drive_invalid_val : std_logic; + p_ready_high_probability : real range 0.0 to 1.0; end record; constant apb_slave_logger : logger_t := get_logger("vunit_lib:apb_slave_pkg"); impure function new_apb_slave( memory : memory_t; - ready_high_probability : real := 1.0; - logger : logger_t := apb_slave_logger) + logger : logger_t := bus_logger; + actor : actor_t := null_actor; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X'; + ready_high_probability : real := 1.0) return apb_slave_t; constant slave_write_msg : msg_type_t := new_msg_type("apb slave write"); @@ -39,15 +45,21 @@ package body apb_slave_pkg is impure function new_apb_slave( memory : memory_t; - ready_high_probability : real := 1.0; - logger : logger_t := apb_slave_logger) + logger : logger_t := bus_logger; + actor : actor_t := null_actor; + drive_invalid : boolean := true; + drive_invalid_val : std_logic := 'X'; + ready_high_probability : real := 1.0) return apb_slave_t is begin - return (p_actor => new_actor, - p_memory => to_vc_interface(memory, logger), - p_logger => logger, - ready_high_probability => ready_high_probability - ); + return ( + p_memory => to_vc_interface(memory, logger), + p_logger => logger, + p_actor => new_actor, + p_drive_invalid => drive_invalid, + p_drive_invalid_val => drive_invalid_val, + p_ready_high_probability => ready_high_probability + ); end; end package body; \ No newline at end of file From e3c1ec377a062cc5d9f6b861baa67762b7a5299b Mon Sep 17 00:00:00 2001 From: c-thaler Date: Tue, 29 Oct 2024 01:55:07 +0100 Subject: [PATCH 12/23] use null_actor/null_logger as defaults for master --- .../src/apb_master_pkg.vhd | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd index f7bff7fd3..500ed0164 100644 --- a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd @@ -22,17 +22,15 @@ package apb_master_pkg is p_bus_handle : bus_master_t; p_drive_invalid : boolean; p_drive_invalid_val : std_logic; - p_ready_high_probability : real range 0.0 to 1.0; end record; impure function new_apb_master( data_length : natural; address_length : natural; - logger : logger_t := bus_logger; + logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; - drive_invalid_val : std_logic := 'X'; - ready_high_probability : real := 1.0 + drive_invalid_val : std_logic := 'X' ) return apb_master_t; function get_logger(bus_handle : apb_master_t) return logger_t; @@ -116,24 +114,37 @@ package body apb_master_pkg is impure function new_apb_master( data_length : natural; address_length : natural; - logger : logger_t := bus_logger; + logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; - drive_invalid_val : std_logic := 'X'; - ready_high_probability : real := 1.0 + drive_invalid_val : std_logic := 'X' ) return apb_master_t is - variable bus_handle : bus_master_t := new_bus( - data_length => data_length, - address_length => address_length, - logger => logger, - actor => actor - ); + impure function create_bus (logger : logger_t; actor : actor_t) return bus_master_t is + begin + return new_bus( + data_length => data_length, + address_length => address_length, + logger => logger, + actor => actor + ); + end function; + variable actor_tmp : actor_t := null_actor; + variable logger_tmp : logger_t := null_logger; begin + if actor = null_actor then + actor_tmp := new_actor; + else + actor_tmp := actor; + end if; + if logger = null_logger then + logger_tmp := bus_logger; + else + logger_tmp := logger; + end if; return ( - p_bus_handle => bus_handle, + p_bus_handle => create_bus(logger_tmp, actor_tmp), p_drive_invalid => drive_invalid, - p_drive_invalid_val => drive_invalid_val, - p_ready_high_probability => ready_high_probability + p_drive_invalid_val => drive_invalid_val ); end; From a69abfe140698dc40f8116fb4c9bdbc93251447e Mon Sep 17 00:00:00 2001 From: c-thaler Date: Tue, 29 Oct 2024 01:58:56 +0100 Subject: [PATCH 13/23] use null_logger as default for apb slave --- .../src/apb_slave_pkg.vhd | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd index 5e00046e4..54adb5f71 100644 --- a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd @@ -30,7 +30,7 @@ package apb_slave_pkg is constant apb_slave_logger : logger_t := get_logger("vunit_lib:apb_slave_pkg"); impure function new_apb_slave( memory : memory_t; - logger : logger_t := bus_logger; + logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X'; @@ -45,17 +45,29 @@ package body apb_slave_pkg is impure function new_apb_slave( memory : memory_t; - logger : logger_t := bus_logger; + logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X'; ready_high_probability : real := 1.0) return apb_slave_t is + variable actor_tmp : actor_t := null_actor; + variable logger_tmp : logger_t := null_logger; begin + if actor = null_actor then + actor_tmp := new_actor; + else + actor_tmp := actor; + end if; + if logger = null_logger then + logger_tmp := bus_logger; + else + logger_tmp := logger; + end if; return ( p_memory => to_vc_interface(memory, logger), - p_logger => logger, - p_actor => new_actor, + p_logger => logger_tmp, + p_actor => actor_tmp, p_drive_invalid => drive_invalid, p_drive_invalid_val => drive_invalid_val, p_ready_high_probability => ready_high_probability From 839edf01ac4ec4f9ec77d5e4fc80189b32d1064f Mon Sep 17 00:00:00 2001 From: c-thaler Date: Tue, 29 Oct 2024 02:01:31 +0100 Subject: [PATCH 14/23] let the apb_master ctor be handled by bus_master The bus_master implementation will create an actor if null_actor is given as parameter. So we don't have to do it in apb_master. --- .../verification_components/src/apb_master_pkg.vhd | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd index 500ed0164..3f73745c4 100644 --- a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd @@ -119,7 +119,7 @@ package body apb_master_pkg is drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X' ) return apb_master_t is - impure function create_bus (logger : logger_t; actor : actor_t) return bus_master_t is + impure function create_bus (logger : logger_t) return bus_master_t is begin return new_bus( data_length => data_length, @@ -128,21 +128,15 @@ package body apb_master_pkg is actor => actor ); end function; - variable actor_tmp : actor_t := null_actor; variable logger_tmp : logger_t := null_logger; begin - if actor = null_actor then - actor_tmp := new_actor; - else - actor_tmp := actor; - end if; if logger = null_logger then logger_tmp := bus_logger; else logger_tmp := logger; end if; return ( - p_bus_handle => create_bus(logger_tmp, actor_tmp), + p_bus_handle => create_bus(logger_tmp), p_drive_invalid => drive_invalid, p_drive_invalid_val => drive_invalid_val ); From 043ba5e00df4aa997c2e91e6cd53f9379a20796e Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 1 Nov 2024 22:25:12 +0200 Subject: [PATCH 15/23] lock test_runner_cleanup entry gate Keep it locked while there is unfinished work to do. --- vunit/vhdl/verification_components/src/apb_master.vhd | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_master.vhd index 70d3d7880..609619e2c 100644 --- a/vunit/vhdl/verification_components/src/apb_master.vhd +++ b/vunit/vhdl/verification_components/src/apb_master.vhd @@ -15,6 +15,9 @@ use work.com_types_pkg.all; use work.queue_pkg.all; use work.sync_pkg.all; use work.logger_pkg.all; +use work.runner_pkg.all; +use work.run_pkg.all; +use work.run_types_pkg.all; use work.log_levels_pkg.all; use work.apb_master_pkg.all; @@ -89,14 +92,17 @@ begin variable msg_type : msg_type_t; variable addr_this_transaction : std_logic_vector(paddr_o'range) := (others => '0'); variable data_this_transaction : std_logic_vector(prdata_i'range) := (others => '0'); + constant key : key_t := get_entry_key(test_runner_cleanup); begin loop drive_bus_invalid; psel_o <= '0'; if is_empty(message_queue) then + unlock(runner, key); wait until rising_edge(clk) and not is_empty(message_queue); end if; + lock(runner, key); idle_bus <= false; wait for 0 ns; From e7005bc219f829dc47adf7445636a6533c65252c Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 1 Nov 2024 23:25:49 +0200 Subject: [PATCH 16/23] add support for sync interface --- .../src/apb_master.vhd | 7 ++++ .../src/apb_master_pkg.vhd | 32 +++++++++++++------ .../test/tb_apb_master.vhd | 10 ++++++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_master.vhd index 609619e2c..af1beacee 100644 --- a/vunit/vhdl/verification_components/src/apb_master.vhd +++ b/vunit/vhdl/verification_components/src/apb_master.vhd @@ -71,6 +71,8 @@ begin wait until is_idle and queues_empty and rising_edge(clk); end if; handle_wait_until_idle(net, msg_type, request_msg); + elsif msg_type = wait_for_time_msg then + push(message_queue, request_msg); else unexpected_msg_type(msg_type); end if; @@ -144,6 +146,11 @@ begin reply_msg := new_msg; push_std_ulogic_vector(reply_msg, prdata_i); reply(net, request_msg, reply_msg); + + elsif msg_type = wait_for_time_msg then + handle_wait_for_time(net, msg_type, request_msg); + -- Re-align with the clock when a wait for time message was handled, because this breaks edge alignment. + wait until rising_edge(clk); end if; idle_bus <= true; diff --git a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd index 3f73745c4..1ae693ee4 100644 --- a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd @@ -12,6 +12,7 @@ use work.bus_master_pkg.all; use work.com_pkg.all; use work.com_types_pkg.all; use work.logger_pkg.all; +use work.sync_pkg.all; use work.memory_pkg.memory_t; use work.memory_pkg.to_vc_interface; @@ -49,9 +50,6 @@ package apb_master_pkg is -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); - procedure wait_until_idle(signal net : inout network_t; - bus_handle : apb_master_t); - -- Non blocking: Read the bus returning a reference to the future reply procedure read_bus(signal net : inout network_t; constant bus_handle : apb_master_t; @@ -107,6 +105,14 @@ package apb_master_pkg is value : std_logic; timeout : delay_length := delay_length'high; msg : string := ""); + + procedure wait_until_idle(signal net : inout network_t; + handle : apb_master_t; + timeout : delay_length := max_timeout); + + procedure wait_for_time(signal net : inout network_t; + handle : apb_master_t; + delay : delay_length); end package; package body apb_master_pkg is @@ -168,12 +174,6 @@ package body apb_master_pkg is write_bus(net, bus_handle.p_bus_handle, address, data, byte_enable); end procedure; - procedure wait_until_idle(signal net : inout network_t; - bus_handle : apb_master_t) is - begin - wait_until_idle(net, bus_handle.P_bus_handle); - end procedure; - -- Blocking: read bus with immediate reply procedure read_bus(signal net : inout network_t; constant bus_handle : apb_master_t; @@ -252,4 +252,18 @@ package body apb_master_pkg is begin wait_until_read_bit_equals(net, bus_handle.p_bus_handle, addr, idx, value, timeout, msg); end procedure; + + procedure wait_until_idle(signal net : inout network_t; + handle : apb_master_t; + timeout : delay_length := max_timeout) is + begin + wait_until_idle(net, handle.p_bus_handle.p_actor, timeout); + end procedure; + + procedure wait_for_time(signal net : inout network_t; + handle : apb_master_t; + delay : delay_length) is + begin + wait_for_time(net, handle.p_bus_handle.p_actor, delay); + end procedure; end package body; \ No newline at end of file diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd index 719e96f30..1a75d7d65 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -116,6 +116,16 @@ begin wait_until_idle(net, bus_handle); check_expected_was_written(memory); + elsif run("wait_between_writes") then + buf := allocate(memory => memory, num_bytes => 4, permissions => write_only); + set_expected_word(memory, base_address(buf), x"1234"); + set_expected_word(memory, base_address(buf)+2, x"5678"); + write_bus(net, bus_handle, base_address(buf), x"1234"); + wait_for_time(net, bus_handle, 500 ns); + write_bus(net, bus_handle, base_address(buf)+2, x"5678"); + wait_until_idle(net, bus_handle); + check_expected_was_written(memory); + end if; wait for 100 ns; From bf15f576269b72f1b214ce7ae0aecf391a5f3db3 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Sun, 3 Nov 2024 11:41:07 +0200 Subject: [PATCH 17/23] fix whitespace issues --- vunit/vhdl/verification_components/src/apb_master.vhd | 8 ++++---- vunit/vhdl/verification_components/src/apb_master_pkg.vhd | 6 +++--- vunit/vhdl/verification_components/src/apb_slave.vhd | 4 ++-- vunit/vhdl/verification_components/src/apb_slave_pkg.vhd | 1 - vunit/vhdl/verification_components/test/tb_apb_master.vhd | 4 ++-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_master.vhd index af1beacee..f76ccab92 100644 --- a/vunit/vhdl/verification_components/src/apb_master.vhd +++ b/vunit/vhdl/verification_components/src/apb_master.vhd @@ -57,7 +57,7 @@ begin PROC_MAIN: process variable request_msg : msg_t; variable msg_type : msg_type_t; - begin + begin DISPATCH_LOOP : loop receive(net, bus_handle.p_bus_handle.p_actor, request_msg); msg_type := message_type(request_msg); @@ -133,16 +133,16 @@ begin elsif msg_type = bus_read_msg then addr_this_transaction := pop_std_ulogic_vector(request_msg); - + psel_o <= '1'; penable_o <= '0'; pwrite_o <= '0'; paddr_o <= addr_this_transaction; - + wait until rising_edge(clk); penable_o <= '1'; wait until (pready_i and penable_o) = '1' and rising_edge(clk); - + reply_msg := new_msg; push_std_ulogic_vector(reply_msg, prdata_i); reply(net, request_msg, reply_msg); diff --git a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd index 1ae693ee4..d87ed302c 100644 --- a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_master_pkg.vhd @@ -66,7 +66,7 @@ package apb_master_pkg is constant bus_handle : apb_master_t; constant address : std_logic_vector; variable data : inout std_logic_vector); - + procedure read_bus(signal net : inout network_t; constant bus_handle : apb_master_t; constant address : natural; @@ -78,7 +78,7 @@ package apb_master_pkg is constant address : std_logic_vector; constant expected : std_logic_vector; constant msg : string := ""); - + procedure check_bus(signal net : inout network_t; constant bus_handle : apb_master_t; constant address : natural; @@ -225,7 +225,7 @@ package body apb_master_pkg is begin check_bus(net, bus_handle.p_bus_handle, address, expected, msg); end procedure; - + -- Blocking: Wait until a read from address equals the value using -- std_match If timeout is reached error with msg procedure wait_until_read_equals( diff --git a/vunit/vhdl/verification_components/src/apb_slave.vhd b/vunit/vhdl/verification_components/src/apb_slave.vhd index b4b61a7a4..cd9d82ec2 100644 --- a/vunit/vhdl/verification_components/src/apb_slave.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave.vhd @@ -33,7 +33,7 @@ entity apb_slave is end entity; architecture a of apb_slave is - + begin PROC_MAIN: process @@ -77,7 +77,7 @@ begin if penable_i = '0' then failure(bus_handle.p_logger, "penable_i must be active in the ACCESS phase."); - end if; + end if; end loop; end process; diff --git a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd index 54adb5f71..a2d56c87e 100644 --- a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd @@ -73,5 +73,4 @@ package body apb_slave_pkg is p_ready_high_probability => ready_high_probability ); end; - end package body; \ No newline at end of file diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_master.vhd index 1a75d7d65..1f347eb79 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_master.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_master.vhd @@ -137,7 +137,7 @@ begin U_DUT_MASTER: entity work.apb_master generic map ( - bus_handle => bus_handle + bus_handle => bus_handle ) port map ( clk => clk, @@ -153,7 +153,7 @@ begin U_DUT_SLAVE: entity work.apb_slave generic map ( - bus_handle => slave_handle + bus_handle => slave_handle ) port map ( clk => clk, From 8d84a0308b5deb784743112ea97a5cfd38d0b233 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Sun, 3 Nov 2024 21:24:03 +0200 Subject: [PATCH 18/23] rename APB files according to specification --- .../src/{apb_slave.vhd => apb_completer.vhd} | 0 .../src/{apb_slave_pkg.vhd => apb_completer_pkg.vhd} | 0 .../src/{apb_master.vhd => apb_requester.vhd} | 0 .../src/{apb_master_pkg.vhd => apb_requester_pkg.vhd} | 0 .../test/{tb_apb_master.vhd => tb_apb_requester.vhd} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename vunit/vhdl/verification_components/src/{apb_slave.vhd => apb_completer.vhd} (100%) rename vunit/vhdl/verification_components/src/{apb_slave_pkg.vhd => apb_completer_pkg.vhd} (100%) rename vunit/vhdl/verification_components/src/{apb_master.vhd => apb_requester.vhd} (100%) rename vunit/vhdl/verification_components/src/{apb_master_pkg.vhd => apb_requester_pkg.vhd} (100%) rename vunit/vhdl/verification_components/test/{tb_apb_master.vhd => tb_apb_requester.vhd} (100%) diff --git a/vunit/vhdl/verification_components/src/apb_slave.vhd b/vunit/vhdl/verification_components/src/apb_completer.vhd similarity index 100% rename from vunit/vhdl/verification_components/src/apb_slave.vhd rename to vunit/vhdl/verification_components/src/apb_completer.vhd diff --git a/vunit/vhdl/verification_components/src/apb_slave_pkg.vhd b/vunit/vhdl/verification_components/src/apb_completer_pkg.vhd similarity index 100% rename from vunit/vhdl/verification_components/src/apb_slave_pkg.vhd rename to vunit/vhdl/verification_components/src/apb_completer_pkg.vhd diff --git a/vunit/vhdl/verification_components/src/apb_master.vhd b/vunit/vhdl/verification_components/src/apb_requester.vhd similarity index 100% rename from vunit/vhdl/verification_components/src/apb_master.vhd rename to vunit/vhdl/verification_components/src/apb_requester.vhd diff --git a/vunit/vhdl/verification_components/src/apb_master_pkg.vhd b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd similarity index 100% rename from vunit/vhdl/verification_components/src/apb_master_pkg.vhd rename to vunit/vhdl/verification_components/src/apb_requester_pkg.vhd diff --git a/vunit/vhdl/verification_components/test/tb_apb_master.vhd b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd similarity index 100% rename from vunit/vhdl/verification_components/test/tb_apb_master.vhd rename to vunit/vhdl/verification_components/test/tb_apb_requester.vhd From b156f165a2b9921c48c0c92d5a15576d64c23c3f Mon Sep 17 00:00:00 2001 From: c-thaler Date: Sun, 3 Nov 2024 21:31:20 +0200 Subject: [PATCH 19/23] rename entities according to spec --- .../src/apb_completer.vhd | 8 +-- .../src/apb_completer_pkg.vhd | 16 ++--- .../src/apb_requester.vhd | 8 +-- .../src/apb_requester_pkg.vhd | 66 +++++++++---------- .../test/tb_apb_requester.vhd | 16 ++--- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_completer.vhd b/vunit/vhdl/verification_components/src/apb_completer.vhd index cd9d82ec2..c4d17d6f0 100644 --- a/vunit/vhdl/verification_components/src/apb_completer.vhd +++ b/vunit/vhdl/verification_components/src/apb_completer.vhd @@ -12,12 +12,12 @@ library osvvm; use osvvm.RandomPkg.RandomPType; use work.memory_pkg.all; -use work.apb_slave_pkg.all; +use work.apb_completer_pkg.all; use work.logger_pkg.all; -entity apb_slave is +entity apb_completer is generic ( - bus_handle : apb_slave_t + bus_handle : apb_completer_t ); port ( clk : in std_logic; @@ -32,7 +32,7 @@ entity apb_slave is ); end entity; -architecture a of apb_slave is +architecture a of apb_completer is begin diff --git a/vunit/vhdl/verification_components/src/apb_completer_pkg.vhd b/vunit/vhdl/verification_components/src/apb_completer_pkg.vhd index a2d56c87e..7564646a1 100644 --- a/vunit/vhdl/verification_components/src/apb_completer_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_completer_pkg.vhd @@ -15,9 +15,9 @@ use work.logger_pkg.all; use work.memory_pkg.memory_t; use work.memory_pkg.to_vc_interface; -package apb_slave_pkg is +package apb_completer_pkg is - type apb_slave_t is record + type apb_completer_t is record -- Private p_actor : actor_t; p_memory : memory_t; @@ -27,30 +27,30 @@ package apb_slave_pkg is p_ready_high_probability : real range 0.0 to 1.0; end record; - constant apb_slave_logger : logger_t := get_logger("vunit_lib:apb_slave_pkg"); - impure function new_apb_slave( + constant apb_completer_logger : logger_t := get_logger("vunit_lib:apb_completer_pkg"); + impure function new_apb_completer( memory : memory_t; logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X'; ready_high_probability : real := 1.0) - return apb_slave_t; + return apb_completer_t; constant slave_write_msg : msg_type_t := new_msg_type("apb slave write"); constant slave_read_msg : msg_type_t := new_msg_type("apb slave read"); end package; -package body apb_slave_pkg is +package body apb_completer_pkg is - impure function new_apb_slave( + impure function new_apb_completer( memory : memory_t; logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X'; ready_high_probability : real := 1.0) - return apb_slave_t is + return apb_completer_t is variable actor_tmp : actor_t := null_actor; variable logger_tmp : logger_t := null_logger; begin diff --git a/vunit/vhdl/verification_components/src/apb_requester.vhd b/vunit/vhdl/verification_components/src/apb_requester.vhd index f76ccab92..622adceb4 100644 --- a/vunit/vhdl/verification_components/src/apb_requester.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester.vhd @@ -19,11 +19,11 @@ use work.runner_pkg.all; use work.run_pkg.all; use work.run_types_pkg.all; use work.log_levels_pkg.all; -use work.apb_master_pkg.all; +use work.apb_requester_pkg.all; -entity apb_master is +entity apb_requester is generic ( - bus_handle : apb_master_t + bus_handle : apb_requester_t ); port ( clk : in std_logic; @@ -38,7 +38,7 @@ entity apb_master is ); end entity; -architecture behav of apb_master is +architecture behav of apb_requester is constant message_queue : queue_t := new_queue; signal idle_bus : boolean := true; diff --git a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd index d87ed302c..ef6999a28 100644 --- a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd @@ -16,35 +16,35 @@ use work.sync_pkg.all; use work.memory_pkg.memory_t; use work.memory_pkg.to_vc_interface; -package apb_master_pkg is +package apb_requester_pkg is - type apb_master_t is record + type apb_requester_t is record -- Private p_bus_handle : bus_master_t; p_drive_invalid : boolean; p_drive_invalid_val : std_logic; end record; - impure function new_apb_master( + impure function new_apb_requester( data_length : natural; address_length : natural; logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X' - ) return apb_master_t; + ) return apb_requester_t; - function get_logger(bus_handle : apb_master_t) return logger_t; + function get_logger(bus_handle : apb_requester_t) return logger_t; -- Blocking: Write the bus procedure write_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant data : std_logic_vector; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); procedure write_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; constant data : std_logic_vector; -- default byte enable is all bytes @@ -52,35 +52,35 @@ package apb_master_pkg is -- Non blocking: Read the bus returning a reference to the future reply procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable reference : inout bus_reference_t); procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; variable reference : inout bus_reference_t); -- Blocking: read bus with immediate reply procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable data : inout std_logic_vector); procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; variable data : inout std_logic_vector); -- Blocking: Read bus and check result against expected data procedure check_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant expected : std_logic_vector; constant msg : string := ""); procedure check_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; constant expected : std_logic_vector; constant msg : string := ""); @@ -89,7 +89,7 @@ package apb_master_pkg is -- std_match If timeout is reached error with msg procedure wait_until_read_equals( signal net : inout network_t; - bus_handle : apb_master_t; + bus_handle : apb_requester_t; addr : std_logic_vector; value : std_logic_vector; timeout : delay_length := delay_length'high; @@ -99,7 +99,7 @@ package apb_master_pkg is -- index set to value If timeout is reached error with msg procedure wait_until_read_bit_equals( signal net : inout network_t; - bus_handle : apb_master_t; + bus_handle : apb_requester_t; addr : std_logic_vector; idx : natural; value : std_logic; @@ -107,24 +107,24 @@ package apb_master_pkg is msg : string := ""); procedure wait_until_idle(signal net : inout network_t; - handle : apb_master_t; + handle : apb_requester_t; timeout : delay_length := max_timeout); procedure wait_for_time(signal net : inout network_t; - handle : apb_master_t; + handle : apb_requester_t; delay : delay_length); end package; -package body apb_master_pkg is +package body apb_requester_pkg is - impure function new_apb_master( + impure function new_apb_requester( data_length : natural; address_length : natural; logger : logger_t := null_logger; actor : actor_t := null_actor; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X' - ) return apb_master_t is + ) return apb_requester_t is impure function create_bus (logger : logger_t) return bus_master_t is begin return new_bus( @@ -148,14 +148,14 @@ package body apb_master_pkg is ); end; - function get_logger(bus_handle : apb_master_t) return logger_t is + function get_logger(bus_handle : apb_requester_t) return logger_t is begin return get_logger(bus_handle.p_bus_handle); end function; -- Blocking: Write the bus procedure write_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant data : std_logic_vector; -- default byte enable is all bytes @@ -165,7 +165,7 @@ package body apb_master_pkg is end procedure; procedure write_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; constant data : std_logic_vector; -- default byte enable is all bytes @@ -176,7 +176,7 @@ package body apb_master_pkg is -- Blocking: read bus with immediate reply procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable data : inout std_logic_vector) is begin @@ -184,7 +184,7 @@ package body apb_master_pkg is end procedure; procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; variable data : inout std_logic_vector) is begin @@ -192,7 +192,7 @@ package body apb_master_pkg is end procedure; procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; variable reference : inout bus_reference_t) is begin @@ -200,7 +200,7 @@ package body apb_master_pkg is end procedure; procedure read_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable reference : inout bus_reference_t) is begin @@ -209,7 +209,7 @@ package body apb_master_pkg is -- Blocking: Read bus and check result against expected data procedure check_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant expected : std_logic_vector; constant msg : string := "") is @@ -218,7 +218,7 @@ package body apb_master_pkg is end procedure; procedure check_bus(signal net : inout network_t; - constant bus_handle : apb_master_t; + constant bus_handle : apb_requester_t; constant address : natural; constant expected : std_logic_vector; constant msg : string := "") is @@ -230,7 +230,7 @@ package body apb_master_pkg is -- std_match If timeout is reached error with msg procedure wait_until_read_equals( signal net : inout network_t; - bus_handle : apb_master_t; + bus_handle : apb_requester_t; addr : std_logic_vector; value : std_logic_vector; timeout : delay_length := delay_length'high; @@ -243,7 +243,7 @@ package body apb_master_pkg is -- index set to value If timeout is reached error with msg procedure wait_until_read_bit_equals( signal net : inout network_t; - bus_handle : apb_master_t; + bus_handle : apb_requester_t; addr : std_logic_vector; idx : natural; value : std_logic; @@ -254,14 +254,14 @@ package body apb_master_pkg is end procedure; procedure wait_until_idle(signal net : inout network_t; - handle : apb_master_t; + handle : apb_requester_t; timeout : delay_length := max_timeout) is begin wait_until_idle(net, handle.p_bus_handle.p_actor, timeout); end procedure; procedure wait_for_time(signal net : inout network_t; - handle : apb_master_t; + handle : apb_requester_t; delay : delay_length) is begin wait_for_time(net, handle.p_bus_handle.p_actor, delay); diff --git a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd index 1f347eb79..9ea03b2d5 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd @@ -12,20 +12,20 @@ context work.vunit_context; context work.com_context; use work.memory_pkg.all; use work.bus_master_pkg.all; -use work.apb_slave_pkg.all; -use work.apb_master_pkg.all; +use work.apb_completer_pkg.all; +use work.apb_requester_pkg.all; use work.logger_pkg.all; library osvvm; use osvvm.RandomPkg.all; -entity tb_apb_master is +entity tb_apb_requester is generic ( runner_cfg : string ); end entity; -architecture a of tb_apb_master is +architecture a of tb_apb_requester is constant BUS_DATA_WIDTH : natural := 16; constant BUS_ADDRESS_WIDTH : natural := 32; @@ -40,10 +40,10 @@ architecture a of tb_apb_master is signal prdata : std_logic_vector(BUS_DATA_WIDTH-1 downto 0); signal pready : std_logic := '0'; - constant bus_handle : apb_master_t := new_apb_master(data_length => pwdata'length, + constant bus_handle : apb_requester_t := new_apb_requester(data_length => pwdata'length, address_length => paddr'length); constant memory : memory_t := new_memory; - constant slave_handle : apb_slave_t := new_apb_slave(memory => memory, + constant slave_handle : apb_completer_t := new_apb_completer(memory => memory, logger => get_logger("apb slave"), ready_high_probability => 0.5); @@ -135,7 +135,7 @@ begin end process; test_runner_watchdog(runner, 100 us); - U_DUT_MASTER: entity work.apb_master + U_DUT_MASTER: entity work.apb_requester generic map ( bus_handle => bus_handle ) @@ -151,7 +151,7 @@ begin pready_i => pready ); - U_DUT_SLAVE: entity work.apb_slave + U_DUT_SLAVE: entity work.apb_completer generic map ( bus_handle => slave_handle ) From e44e31393e54611bfca1876d6b7775094b65e295 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Thu, 7 Nov 2024 23:38:40 +0200 Subject: [PATCH 20/23] implement support for pslverror Major change to support optional pslverror signal of APB3. --- .../src/apb_requester.vhd | 24 +++-- .../src/apb_requester_pkg.vhd | 90 ++++++++++++++++--- 2 files changed, 94 insertions(+), 20 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_requester.vhd b/vunit/vhdl/verification_components/src/apb_requester.vhd index 622adceb4..4c53034a2 100644 --- a/vunit/vhdl/verification_components/src/apb_requester.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester.vhd @@ -34,7 +34,8 @@ entity apb_requester is pwrite_o : out std_logic; pwdata_o : out std_logic_vector(data_length(bus_handle.p_bus_handle) - 1 downto 0); prdata_i : in std_logic_vector(data_length(bus_handle.p_bus_handle) - 1 downto 0); - pready_i : in std_logic + pready_i : in std_logic; + pslverr_i : in std_logic := '0' ); end entity; @@ -62,9 +63,8 @@ begin receive(net, bus_handle.p_bus_handle.p_actor, request_msg); msg_type := message_type(request_msg); - if msg_type = bus_read_msg then - push(message_queue, request_msg); - elsif msg_type = bus_write_msg then + if msg_type = bus_read_msg or msg_type = apb_read_msg + or msg_type = bus_write_msg or msg_type = apb_write_msg then push(message_queue, request_msg); elsif msg_type = wait_until_idle_msg then if not is_idle or not queues_empty then @@ -94,6 +94,8 @@ begin variable msg_type : msg_type_t; variable addr_this_transaction : std_logic_vector(paddr_o'range) := (others => '0'); variable data_this_transaction : std_logic_vector(prdata_i'range) := (others => '0'); + variable byte_enable_this_transaction : std_logic_vector(byte_enable_length(bus_handle)-1 downto 0); + variable error_this_transaction : std_logic := '0'; constant key : key_t := get_entry_key(test_runner_cleanup); begin loop @@ -111,9 +113,11 @@ begin request_msg := pop(message_queue); msg_type := message_type(request_msg); - if msg_type = bus_write_msg then + if msg_type = apb_write_msg then addr_this_transaction := pop_std_ulogic_vector(request_msg); data_this_transaction := pop_std_ulogic_vector(request_msg); + byte_enable_this_transaction := pop_std_ulogic_vector(request_msg); + error_this_transaction := pop_std_ulogic(request_msg); psel_o <= '1'; penable_o <= '0'; @@ -125,14 +129,20 @@ begin penable_o <= '1'; wait until (pready_i and penable_o) = '1' and rising_edge(clk); + check_equal(pslverr_i, error_this_transaction, "Unexpected error response."); + if is_visible(bus_handle.p_bus_handle.p_logger, debug) then debug(bus_handle.p_bus_handle.p_logger, "Wrote 0x" & to_hstring(data_this_transaction) & " to address 0x" & to_hstring(addr_this_transaction)); end if; - elsif msg_type = bus_read_msg then + reply_msg := new_msg; + reply(net, request_msg, reply_msg); + + elsif msg_type = apb_read_msg then addr_this_transaction := pop_std_ulogic_vector(request_msg); + error_this_transaction := pop_std_ulogic(request_msg); psel_o <= '1'; penable_o <= '0'; @@ -143,6 +153,8 @@ begin penable_o <= '1'; wait until (pready_i and penable_o) = '1' and rising_edge(clk); + check_equal(pslverr_i, error_this_transaction, "Unexpected error response."); + reply_msg := new_msg; push_std_ulogic_vector(reply_msg, prdata_i); reply(net, request_msg, reply_msg); diff --git a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd index ef6999a28..0dcc4bb7c 100644 --- a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd @@ -36,17 +36,21 @@ package apb_requester_pkg is function get_logger(bus_handle : apb_requester_t) return logger_t; + impure function byte_enable_length(bus_handle : apb_requester_t) return natural; + -- Blocking: Write the bus procedure write_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant data : std_logic_vector; + variable expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); procedure write_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; constant data : std_logic_vector; + variable expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); @@ -54,23 +58,27 @@ package apb_requester_pkg is procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; - variable reference : inout bus_reference_t); + variable reference : inout bus_reference_t; + variable expected_error : std_logic := '0'); procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; - variable reference : inout bus_reference_t); + variable reference : inout bus_reference_t; + variable expected_error : std_logic := '0'); -- Blocking: read bus with immediate reply procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; - variable data : inout std_logic_vector); + variable data : inout std_logic_vector; + variable expected_error : std_logic := '0'); procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; - variable data : inout std_logic_vector); + variable data : inout std_logic_vector; + variable expected_error : std_logic := '0'); -- Blocking: Read bus and check result against expected data procedure check_bus(signal net : inout network_t; @@ -113,6 +121,9 @@ package apb_requester_pkg is procedure wait_for_time(signal net : inout network_t; handle : apb_requester_t; delay : delay_length); + + constant apb_write_msg : msg_type_t := new_msg_type("write apb bus"); + constant apb_read_msg : msg_type_t := new_msg_type("read apb bus"); end package; package body apb_requester_pkg is @@ -153,58 +164,109 @@ package body apb_requester_pkg is return get_logger(bus_handle.p_bus_handle); end function; + impure function address_length(bus_handle : apb_requester_t) return natural is + begin + return bus_handle.p_bus_handle.p_address_length; + end; + + impure function byte_enable_length(bus_handle : apb_requester_t) return natural is + begin + return (bus_handle.p_bus_handle.p_data_length + bus_handle.p_bus_handle.p_byte_length - 1) + / bus_handle.p_bus_handle.p_byte_length; + end; + + impure function to_address(constant bus_handle : apb_requester_t; address : natural) return std_logic_vector is + begin + return std_logic_vector(to_unsigned(address, address_length(bus_handle))); + end; + -- Blocking: Write the bus procedure write_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant data : std_logic_vector; + variable expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is + variable request_msg : msg_t := new_msg(apb_write_msg); + variable full_data : std_logic_vector(bus_handle.p_bus_handle.p_data_length-1 downto 0) := (others => '0'); + variable full_address : std_logic_vector(bus_handle.p_bus_handle.p_address_length-1 downto 0) := (others => '0'); + variable full_byte_enable : std_logic_vector(byte_enable_length(bus_handle)-1 downto 0); begin - write_bus(net, bus_handle.p_bus_handle, address, data, byte_enable); + full_address(address'length-1 downto 0) := address; + push_std_ulogic_vector(request_msg, full_address); + + full_data(data'length-1 downto 0) := data; + push_std_ulogic_vector(request_msg, full_data); + + if byte_enable = "" then + full_byte_enable := (others => '1'); + else + full_byte_enable(byte_enable'length-1 downto 0) := byte_enable; + end if; + push_std_ulogic_vector(request_msg, full_byte_enable); + push_std_ulogic(request_msg, expected_error); + + send(net, bus_handle.p_bus_handle.p_actor, request_msg); end procedure; procedure write_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; constant data : std_logic_vector; + variable expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is begin - write_bus(net, bus_handle.p_bus_handle, address, data, byte_enable); + write_bus(net, bus_handle, to_address(bus_handle, address), data, expected_error, byte_enable); end procedure; -- Blocking: read bus with immediate reply procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; - variable data : inout std_logic_vector) is + variable data : inout std_logic_vector; + variable expected_error : std_logic := '0') is + variable reference : bus_reference_t; begin - read_bus(net, bus_handle.p_bus_handle, address, data); + read_bus(net, bus_handle, address, reference, expected_error); + await_read_bus_reply(net, reference, data); end procedure; procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; - variable data : inout std_logic_vector) is + variable data : inout std_logic_vector; + variable expected_error : std_logic := '0') is + variable reference : bus_reference_t; begin - read_bus(net, bus_handle.p_bus_handle, address, data); + read_bus(net, bus_handle, to_address(bus_handle, address), reference, expected_error); + await_read_bus_reply(net, reference, data); end procedure; + -- Non blocking read with delayed reply procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; - variable reference : inout bus_reference_t) is + variable reference : inout bus_reference_t; + variable expected_error : std_logic := '0') is begin - read_bus(net, bus_handle.p_bus_handle, address, reference); + read_bus(net, bus_handle, to_address(bus_handle, address), reference, expected_error); end procedure; procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; - variable reference : inout bus_reference_t) is + variable reference : inout bus_reference_t; + variable expected_error : std_logic := '0') is + variable full_address : std_logic_vector(bus_handle.p_bus_handle.p_address_length-1 downto 0) := (others => '0'); + alias request_msg : msg_t is reference; begin - read_bus(net, bus_handle.p_bus_handle, address, reference); + request_msg := new_msg(apb_read_msg); + full_address(address'length-1 downto 0) := address; + push_std_ulogic_vector(request_msg, full_address); + push_std_ulogic(request_msg, expected_error); + send(net, bus_handle.p_bus_handle.p_actor, request_msg); end procedure; -- Blocking: Read bus and check result against expected data From b1a7968056f2ef740f4a45f92e10253a79e2fa48 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 8 Nov 2024 00:44:50 +0200 Subject: [PATCH 21/23] add pslverror test cases and fix issue --- .../src/apb_requester.vhd | 4 ++-- .../src/apb_requester_pkg.vhd | 24 +++++++++---------- .../test/tb_apb_requester.vhd | 19 +++++++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_requester.vhd b/vunit/vhdl/verification_components/src/apb_requester.vhd index 4c53034a2..fba759ceb 100644 --- a/vunit/vhdl/verification_components/src/apb_requester.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester.vhd @@ -129,7 +129,7 @@ begin penable_o <= '1'; wait until (pready_i and penable_o) = '1' and rising_edge(clk); - check_equal(pslverr_i, error_this_transaction, "Unexpected error response."); + check_equal(pslverr_i, error_this_transaction, "Unexpected pslverror response for write request."); if is_visible(bus_handle.p_bus_handle.p_logger, debug) then debug(bus_handle.p_bus_handle.p_logger, @@ -153,7 +153,7 @@ begin penable_o <= '1'; wait until (pready_i and penable_o) = '1' and rising_edge(clk); - check_equal(pslverr_i, error_this_transaction, "Unexpected error response."); + check_equal(pslverr_i, error_this_transaction, "Unexpected pslverror response for read request."); reply_msg := new_msg; push_std_ulogic_vector(reply_msg, prdata_i); diff --git a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd index 0dcc4bb7c..88e532476 100644 --- a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd @@ -43,14 +43,14 @@ package apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant data : std_logic_vector; - variable expected_error : std_logic := '0'; + constant expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); procedure write_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; constant data : std_logic_vector; - variable expected_error : std_logic := '0'; + constant expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := ""); @@ -59,26 +59,26 @@ package apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable reference : inout bus_reference_t; - variable expected_error : std_logic := '0'); + constant expected_error : std_logic := '0'); procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; variable reference : inout bus_reference_t; - variable expected_error : std_logic := '0'); + constant expected_error : std_logic := '0'); -- Blocking: read bus with immediate reply procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable data : inout std_logic_vector; - variable expected_error : std_logic := '0'); + constant expected_error : std_logic := '0'); procedure read_bus(signal net : inout network_t; constant bus_handle : apb_requester_t; constant address : natural; variable data : inout std_logic_vector; - variable expected_error : std_logic := '0'); + constant expected_error : std_logic := '0'); -- Blocking: Read bus and check result against expected data procedure check_bus(signal net : inout network_t; @@ -185,7 +185,7 @@ package body apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : std_logic_vector; constant data : std_logic_vector; - variable expected_error : std_logic := '0'; + constant expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is variable request_msg : msg_t := new_msg(apb_write_msg); @@ -214,7 +214,7 @@ package body apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : natural; constant data : std_logic_vector; - variable expected_error : std_logic := '0'; + constant expected_error : std_logic := '0'; -- default byte enable is all bytes constant byte_enable : std_logic_vector := "") is begin @@ -226,7 +226,7 @@ package body apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable data : inout std_logic_vector; - variable expected_error : std_logic := '0') is + constant expected_error : std_logic := '0') is variable reference : bus_reference_t; begin read_bus(net, bus_handle, address, reference, expected_error); @@ -237,7 +237,7 @@ package body apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : natural; variable data : inout std_logic_vector; - variable expected_error : std_logic := '0') is + constant expected_error : std_logic := '0') is variable reference : bus_reference_t; begin read_bus(net, bus_handle, to_address(bus_handle, address), reference, expected_error); @@ -249,7 +249,7 @@ package body apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : natural; variable reference : inout bus_reference_t; - variable expected_error : std_logic := '0') is + constant expected_error : std_logic := '0') is begin read_bus(net, bus_handle, to_address(bus_handle, address), reference, expected_error); end procedure; @@ -258,7 +258,7 @@ package body apb_requester_pkg is constant bus_handle : apb_requester_t; constant address : std_logic_vector; variable reference : inout bus_reference_t; - variable expected_error : std_logic := '0') is + constant expected_error : std_logic := '0') is variable full_address : std_logic_vector(bus_handle.p_bus_handle.p_address_length-1 downto 0) := (others => '0'); alias request_msg : msg_t is reference; begin diff --git a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd index 9ea03b2d5..71da9ffd4 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd @@ -126,6 +126,25 @@ begin wait_until_idle(net, bus_handle); check_expected_was_written(memory); + elsif run("pslverror_during_read") then + buf := allocate(memory => memory, num_bytes => 2, permissions => read_only); + write_word(memory, base_address(buf), x"1234"); + mock(get_logger("check"), error); + read_bus(net, bus_handle, base_address(buf), data, '1'); + wait_until_idle(net, bus_handle); + check_only_log(get_logger("check"), + "Unexpected pslverror response for read request. - Got 0. Expected 1.", error); + unmock(get_logger("check")); + + elsif run("pslverror_during_write") then + buf := allocate(memory => memory, num_bytes => 2, permissions => write_only); + mock(get_logger("check"), error); + write_bus(net, bus_handle, base_address(buf), x"1122", '1'); + wait_until_idle(net, bus_handle); + check_only_log(get_logger("check"), + "Unexpected pslverror response for write request. - Got 0. Expected 1.", error); + unmock(get_logger("check")); + end if; wait for 100 ns; From f6fd6e51dbfb87dee148ad6a729dacef8c368a28 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Fri, 8 Nov 2024 23:42:09 +0200 Subject: [PATCH 22/23] fix instance names --- vunit/vhdl/verification_components/test/tb_apb_requester.vhd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd index 71da9ffd4..9051a32e8 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd @@ -154,7 +154,7 @@ begin end process; test_runner_watchdog(runner, 100 us); - U_DUT_MASTER: entity work.apb_requester + U_DUT_REQUESTER: entity work.apb_requester generic map ( bus_handle => bus_handle ) @@ -170,7 +170,7 @@ begin pready_i => pready ); - U_DUT_SLAVE: entity work.apb_completer + U_DUT_COMPLETER: entity work.apb_completer generic map ( bus_handle => slave_handle ) From 2eb54094f45c2628d816de9b8ff957e87495d5f2 Mon Sep 17 00:00:00 2001 From: c-thaler Date: Sat, 9 Nov 2024 00:28:54 +0200 Subject: [PATCH 23/23] add id and unexpected message policy parameter Implementing rules 5 and 10. The logger name is set according to the id field. --- .../src/apb_requester.vhd | 5 ++++- .../src/apb_requester_pkg.vhd | 21 +++++++++++++++++-- .../test/tb_apb_requester.vhd | 9 ++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/vunit/vhdl/verification_components/src/apb_requester.vhd b/vunit/vhdl/verification_components/src/apb_requester.vhd index fba759ceb..eedd67c09 100644 --- a/vunit/vhdl/verification_components/src/apb_requester.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester.vhd @@ -15,6 +15,7 @@ use work.com_types_pkg.all; use work.queue_pkg.all; use work.sync_pkg.all; use work.logger_pkg.all; +use work.vc_pkg.all; use work.runner_pkg.all; use work.run_pkg.all; use work.run_types_pkg.all; @@ -74,7 +75,9 @@ begin elsif msg_type = wait_for_time_msg then push(message_queue, request_msg); else - unexpected_msg_type(msg_type); + if bus_handle.p_unexpected_msg_type_policy = fail then + unexpected_msg_type(msg_type); + end if; end if; end loop; end process; diff --git a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd index 88e532476..e50de5024 100644 --- a/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd +++ b/vunit/vhdl/verification_components/src/apb_requester_pkg.vhd @@ -13,6 +13,8 @@ use work.com_pkg.all; use work.com_types_pkg.all; use work.logger_pkg.all; use work.sync_pkg.all; +use work.id_pkg.all; +use work.vc_pkg.all; use work.memory_pkg.memory_t; use work.memory_pkg.to_vc_interface; @@ -20,16 +22,20 @@ package apb_requester_pkg is type apb_requester_t is record -- Private + p_id : id_t; p_bus_handle : bus_master_t; p_drive_invalid : boolean; p_drive_invalid_val : std_logic; + p_unexpected_msg_type_policy : unexpected_msg_type_policy_t; end record; impure function new_apb_requester( + id : id_t := null_id; data_length : natural; address_length : natural; logger : logger_t := null_logger; actor : actor_t := null_actor; + unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X' ) return apb_requester_t; @@ -129,10 +135,12 @@ end package; package body apb_requester_pkg is impure function new_apb_requester( + id : id_t := null_id; data_length : natural; address_length : natural; logger : logger_t := null_logger; actor : actor_t := null_actor; + unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail; drive_invalid : boolean := true; drive_invalid_val : std_logic := 'X' ) return apb_requester_t is @@ -146,16 +154,25 @@ package body apb_requester_pkg is ); end function; variable logger_tmp : logger_t := null_logger; + variable id_tmp : id_t := null_id; + constant parent : id_t := get_id("vunit_lib:apb_requester"); begin + if id = null_id then + id_tmp := get_id(to_string(num_children(parent) + 1), parent); + else + id_tmp := id; + end if; if logger = null_logger then - logger_tmp := bus_logger; + logger_tmp := get_logger(id_tmp); else logger_tmp := logger; end if; return ( + p_id => id_tmp, p_bus_handle => create_bus(logger_tmp), p_drive_invalid => drive_invalid, - p_drive_invalid_val => drive_invalid_val + p_drive_invalid_val => drive_invalid_val, + p_unexpected_msg_type_policy => unexpected_msg_type_policy ); end; diff --git a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd index 9051a32e8..d78fe11f5 100644 --- a/vunit/vhdl/verification_components/test/tb_apb_requester.vhd +++ b/vunit/vhdl/verification_components/test/tb_apb_requester.vhd @@ -54,6 +54,8 @@ begin variable buf : buffer_t; variable data, data2 : std_logic_vector(prdata'range); variable bus_ref1, bus_ref2 : bus_reference_t; + constant unexpected_message_type : msg_type_t := new_msg_type("unexpected message"); + variable unexpected_message : msg_t := new_msg(unexpected_message_type); begin show(get_logger("apb slave"), display_handler, debug); @@ -145,6 +147,13 @@ begin "Unexpected pslverror response for write request. - Got 0. Expected 1.", error); unmock(get_logger("check")); + elsif run("unexpected_msg_type_policy_fail") then + mock(get_logger("vunit_lib:com"), failure); + send(net, bus_handle.p_bus_handle.p_actor, unexpected_message); + check_only_log(get_logger("vunit_lib:com"), + "Got unexpected message unexpected message", failure); + unmock(get_logger("vunit_lib:com")); + end if; wait for 100 ns;