| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | // Abstract class meant to hold arbitrary virtual interface handles. | 
 | // | 
 | // Written primarily for an interface which implements functional coverage, this could be used | 
 | // for other purposes as well. This abstract class provides utilities & macros to retrieve | 
 | // virtual interface handles that are bound to a DUT's sub-modules. These sub-module interfaces must | 
 | // self-register using the `DV_VIF_WRAP_SET_VIF()` macro (see details below). The extended class | 
 | // then implements the `get_vifs()` method using the `DV_VIF_WRAP_GET_VIF*` macros below to retrieve | 
 | // the sub-module interface handles it maintains. | 
 | virtual class dv_vif_wrap; | 
 |   string hier;  // Represents the hierarchy of the parent module or interface. | 
 |   string name;  // Name of the class instance. | 
 |  | 
 |   function new(string hier, string name = ""); | 
 |     this.hier = hier; | 
 |     this.name = name; | 
 |   endfunction | 
 |  | 
 |   // Abstract method implemented by the extended class. It is recommended to invoke the helper | 
 |   // macros below rather than manually define it. | 
 |   pure virtual task get_vifs(); | 
 |  | 
 | endclass | 
 |  | 
 | // Helper macros. | 
 | // | 
 | // These are defined in the file itself since they are tightly coupled to the class definition | 
 | // above. These are scoped globally so that extended classes can invoke them. | 
 |  | 
 | // Enable an interface to register itself (set its handle into the config db). | 
 | // | 
 | // Meant to be invoked from an interface. The macros invocation causes the interface to register | 
 | // itself into the uvm_resource_db pool. The derived class of dv_vif_wrap retrieves the handle to | 
 | // that interface handle from the uvm_resource db pool. | 
 | // | 
 | // SV LRM does not yet allow referencing the instance of an interface within itself as one | 
 | // would in case of a class using the ~this~ keyword. However, most major simulators actually | 
 | // support this in their own custom way. On VCS, a reference to self within the interface can be set | 
 | // using `interface::self()` construct. On Xcelium, this is achieved by simply referencing the | 
 | // interface name. | 
 | // | 
 | // _IF:    The SV interface | 
 | // _VIF:   The corresponding virtual interface handle name | 
 | // _LEVEL: # of hierarchical levels the module to which the SV interface is bound, starting at the | 
 | //         top level DUT instance. | 
 | `define DV_VIF_WRAP_SET_VIF(_IF, _VIF, _LEVEL = 0) \ | 
 |   import uvm_pkg::*; \ | 
 |   function automatic void self_register(); \ | 
 |     string path; \ | 
 |     virtual _IF vif; \ | 
 |     /* Initial block adds another level in the path hierarchy which needs to be split out. */ \ | 
 |     /* Add one more to go one level up the interface instance. */ \ | 
 |     /* Example: tb.dut.core.u_foo_if.self_register -> tb.dut.core. */ \ | 
 |     path = dv_utils_pkg::get_parent_hier(.hier($sformatf("%m")), .n_levels_up(2 + _LEVEL)); \ | 
 | `ifdef VCS \ | 
 |   vif = interface::self(); \ | 
 | `elsif XCELIUM \ | 
 |   vif = _IF; \ | 
 | `else \ | 
 |   vif = _IF; \ | 
 | `endif \ | 
 |     uvm_pkg::uvm_resource_db#(virtual _IF)::set(path, `"_VIF`", vif); \ | 
 |   endfunction \ | 
 |   initial self_register(); | 
 |  | 
 | // Enables the retrieval of individual vifs. | 
 | // | 
 | // The three macros below go together to define the _get_vifs() task in the extended class. | 
 | `define DV_VIF_WRAP_GET_VIFS_BEGIN \ | 
 |   task get_vifs(); \ | 
 |     fork \ | 
 |  | 
 | // To avoid race condition between the instant when an interface handle is set into the config db | 
 | // and the instant when it is retrieved (in the same time step, at t = 0), the macro below invokes | 
 | // uvm_config_db#(..)::wait_modified() to ensure that the retrieval is done only after the set. | 
 | `define DV_VIF_WRAP_GET_VIF(_IF, _VIF) \ | 
 |     begin \ | 
 |       bit vif_found; \ | 
 |       /* At most 2 retries. */ \ | 
 |       repeat (2) begin \ | 
 |         /* Force the evaluation at the end of the time step. */ \ | 
 |         #0; \ | 
 |         if (uvm_pkg::uvm_resource_db#(virtual _IF)::read_by_name(hier, `"_VIF`", _VIF)) begin \ | 
 |           vif_found = 1'b1; \ | 
 |           break; \ | 
 |         end \ | 
 |       end \ | 
 |       `DV_CHECK_FATAL(vif_found, {`"_VIF`", " not found in the resource db"}, hier) \ | 
 |     end | 
 |  | 
 | `define DV_VIF_WRAP_GET_VIFS_END \ | 
 |     join \ | 
 |   endtask |