| //---------------------------------------------------------------------- |
| // Copyright 2007-2011 Mentor Graphics Corporation |
| // Copyright 2007-2010 Cadence Design Systems, Inc. |
| // Copyright 2010-2011 Synopsys, Inc. |
| // All Rights Reserved Worldwide |
| // |
| // Licensed under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in |
| // compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in |
| // writing, software distributed under the License is |
| // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
| // CONDITIONS OF ANY KIND, either express or implied. See |
| // the License for the specific language governing |
| // permissions and limitations under the License. |
| //---------------------------------------------------------------------- |
| |
| `include "uvm_macros.svh" |
| |
| `ifndef UVM_CALLBACK_SVH |
| `define UVM_CALLBACK_SVH |
| |
| //------------------------------------------------------------------------------ |
| // Title: Callbacks Classes |
| // |
| // This section defines the classes used for callback registration, management, |
| // and user-defined callbacks. |
| //------------------------------------------------------------------------------ |
| |
| typedef class uvm_root; |
| typedef class uvm_callback; |
| typedef class uvm_callbacks_base; |
| |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Class - uvm_typeid_base |
| // |
| //------------------------------------------------------------------------------ |
| // |
| // Simple typeid interface. Need this to set up the base-super mapping. |
| // This is similar to the factory, but much simpler. The idea of this |
| // interface is that each object type T has a typeid that can be |
| // used for mapping type relationships. This is not a user visible class. |
| |
| class uvm_typeid_base; |
| static string typename; |
| static uvm_callbacks_base typeid_map[uvm_typeid_base]; |
| static uvm_typeid_base type_map[uvm_callbacks_base]; |
| endclass |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Class - uvm_typeid#(T) |
| // |
| //------------------------------------------------------------------------------ |
| |
| class uvm_typeid#(type T=uvm_object) extends uvm_typeid_base; |
| static uvm_typeid#(T) m_b_inst; |
| static function uvm_typeid#(T) get(); |
| if(m_b_inst == null) |
| m_b_inst = new; |
| return m_b_inst; |
| endfunction |
| endclass |
| |
| //------------------------------------------------------------------------------ |
| // Class - uvm_callbacks_base |
| // |
| // Base class singleton that holds generic queues for all instance |
| // specific objects. This is an internal class. This class contains a |
| // global pool that has all of the instance specific callback queues in it. |
| // All of the typewide callback queues live in the derivative class |
| // uvm_typed_callbacks#(T). This is not a user visible class. |
| // |
| // This class holds the class inheritance hierarchy information |
| // (super types and derivative types). |
| // |
| // Note, all derivative uvm_callbacks#() class singletons access this |
| // global m_pool object in order to get access to their specific |
| // instance queue. |
| //------------------------------------------------------------------------------ |
| |
| class uvm_callbacks_base extends uvm_object; |
| |
| typedef uvm_callbacks_base this_type; |
| |
| /*protected*/ static bit m_tracing = 1; |
| static this_type m_b_inst; |
| |
| static uvm_pool#(uvm_object,uvm_queue#(uvm_callback)) m_pool; |
| |
| static function this_type m_initialize(); |
| if(m_b_inst == null) begin |
| m_b_inst = new; |
| m_pool = new; |
| end |
| return m_b_inst; |
| endfunction |
| |
| //Type checking interface |
| this_type m_this_type[$]; //one to many T->T/CB |
| uvm_typeid_base m_super_type; //one to one relation |
| uvm_typeid_base m_derived_types[$]; //one to many relation |
| |
| virtual function bit m_am_i_a(uvm_object obj); |
| return 0; |
| endfunction |
| |
| virtual function bit m_is_for_me(uvm_callback cb); |
| return 0; |
| endfunction |
| |
| virtual function bit m_is_registered(uvm_object obj, uvm_callback cb); |
| return 0; |
| endfunction |
| |
| virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj); |
| return null; |
| endfunction |
| |
| virtual function void m_add_tw_cbs(uvm_callback cb, uvm_apprepend ordering); |
| endfunction |
| |
| virtual function bit m_delete_tw_cbs(uvm_callback cb); |
| return 0; |
| endfunction |
| |
| //Check registration. To test registration, start at this class and |
| //work down the class hierarchy. If any class returns true then |
| //the pair is legal. |
| function bit check_registration(uvm_object obj, uvm_callback cb); |
| this_type st, dt; |
| |
| if (m_is_registered(obj,cb)) |
| return 1; |
| |
| // Need to look at all possible T/CB pairs of this type |
| foreach(m_this_type[i]) |
| if(m_b_inst != m_this_type[i] && m_this_type[i].m_is_registered(obj,cb)) |
| return 1; |
| |
| if(obj == null) begin |
| foreach(m_derived_types[i]) begin |
| dt = uvm_typeid_base::typeid_map[m_derived_types[i] ]; |
| if(dt != null && dt.check_registration(null,cb)) |
| return 1; |
| end |
| end |
| |
| return 0; |
| endfunction |
| |
| endclass |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Class - uvm_typed_callbacks#(T) |
| // |
| //------------------------------------------------------------------------------ |
| // |
| // Another internal class. This contains the queue of typewide |
| // callbacks. It also contains some of the public interface methods, |
| // but those methods are accessed via the uvm_callbacks#() class |
| // so they are documented in that class even though the implementation |
| // is in this class. |
| // |
| // The <add>, <delete>, and <display> methods are implemented in this class. |
| |
| class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; |
| |
| static uvm_queue#(uvm_callback) m_tw_cb_q; |
| static string m_typename; |
| |
| typedef uvm_typed_callbacks#(T) this_type; |
| typedef uvm_callbacks_base super_type; |
| |
| //The actual global object from the derivative class. Note that this is |
| //just a reference to the object that is generated in the derived class. |
| static this_type m_t_inst; |
| |
| static function this_type m_initialize(); |
| if(m_t_inst == null) begin |
| void'(super_type::m_initialize()); |
| m_t_inst = new; |
| m_t_inst.m_tw_cb_q = new("typewide_queue"); |
| end |
| return m_t_inst; |
| endfunction |
| |
| //Type checking interface: is given ~obj~ of type T? |
| virtual function bit m_am_i_a(uvm_object obj); |
| T this_type; |
| if (obj == null) |
| return 1; |
| return($cast(this_type,obj)); |
| endfunction |
| |
| //Getting the typewide queue |
| virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj); |
| if(m_am_i_a(obj)) begin |
| foreach(m_derived_types[i]) begin |
| super_type dt; |
| dt = uvm_typeid_base::typeid_map[m_derived_types[i] ]; |
| if(dt != null && dt != this) begin |
| m_get_tw_cb_q = dt.m_get_tw_cb_q(obj); |
| if(m_get_tw_cb_q != null) |
| return m_get_tw_cb_q; |
| end |
| end |
| return m_t_inst.m_tw_cb_q; |
| end |
| else |
| return null; |
| endfunction |
| |
| static function int m_cb_find(uvm_queue#(uvm_callback) q, uvm_callback cb); |
| for(int i=0; i<q.size(); ++i) |
| if(q.get(i) == cb) |
| return i; |
| return -1; |
| endfunction |
| |
| static function int m_cb_find_name(uvm_queue#(uvm_callback) q, string name, string where); |
| uvm_callback cb; |
| for(int i=0; i<q.size(); ++i) begin |
| cb = q.get(i); |
| if(cb.get_name() == name) begin |
| `uvm_warning("UVM/CB/NAM/SAM", {"A callback named \"", name, |
| "\" is already registered with ", where}) |
| return 1; |
| end |
| end |
| return 0; |
| endfunction |
| |
| //For a typewide callback, need to add to derivative types as well. |
| virtual function void m_add_tw_cbs(uvm_callback cb, uvm_apprepend ordering); |
| super_type cb_pair; |
| uvm_object obj; |
| T me; |
| bit warned; |
| uvm_queue#(uvm_callback) q; |
| if(m_cb_find(m_t_inst.m_tw_cb_q,cb) == -1) begin |
| warned = m_cb_find_name(m_t_inst.m_tw_cb_q, cb.get_name(), "type"); |
| if(ordering == UVM_APPEND) |
| m_t_inst.m_tw_cb_q.push_back(cb); |
| else |
| m_t_inst.m_tw_cb_q.push_front(cb); |
| end |
| if(m_t_inst.m_pool.first(obj)) begin |
| do begin |
| if($cast(me,obj)) begin |
| q = m_t_inst.m_pool.get(obj); |
| if(q==null) begin |
| q=new; |
| m_t_inst.m_pool.add(obj,q); |
| end |
| if(m_cb_find(q,cb) == -1) begin |
| if (!warned) begin |
| void'(m_cb_find_name(q, cb.get_name(), {"object instance ", me.get_full_name()})); |
| end |
| if(ordering == UVM_APPEND) |
| q.push_back(cb); |
| else |
| q.push_front(cb); |
| end |
| end |
| end while(m_t_inst.m_pool.next(obj)); |
| end |
| foreach(m_derived_types[i]) begin |
| cb_pair = uvm_typeid_base::typeid_map[m_derived_types[i] ]; |
| if(cb_pair != this) |
| cb_pair.m_add_tw_cbs(cb,ordering); |
| end |
| endfunction |
| |
| |
| //For a typewide callback, need to remove from derivative types as well. |
| virtual function bit m_delete_tw_cbs(uvm_callback cb); |
| super_type cb_pair; |
| uvm_object obj; |
| uvm_queue#(uvm_callback) q; |
| int pos = m_cb_find(m_t_inst.m_tw_cb_q,cb); |
| |
| if(pos != -1) begin |
| m_t_inst.m_tw_cb_q.delete(pos); |
| m_delete_tw_cbs = 1; |
| end |
| |
| if(m_t_inst.m_pool.first(obj)) begin |
| do begin |
| q = m_t_inst.m_pool.get(obj); |
| if(q==null) begin |
| q=new; |
| m_t_inst.m_pool.add(obj,q); |
| end |
| pos = m_cb_find(q,cb); |
| if(pos != -1) begin |
| q.delete(pos); |
| m_delete_tw_cbs = 1; |
| end |
| end while(m_t_inst.m_pool.next(obj)); |
| end |
| foreach(m_derived_types[i]) begin |
| cb_pair = uvm_typeid_base::typeid_map[m_derived_types[i] ]; |
| if(cb_pair != this) |
| m_delete_tw_cbs |= cb_pair.m_delete_tw_cbs(cb); |
| end |
| endfunction |
| |
| |
| static function void display(T obj=null); |
| T me; |
| super_type ib = m_t_inst; |
| string cbq[$]; |
| string inst_q[$]; |
| string mode_q[$]; |
| uvm_callback cb; |
| string blanks = " "; |
| uvm_object bobj = obj; |
| string qs[$]; |
| |
| uvm_queue#(uvm_callback) q; |
| string tname, str; |
| |
| int max_cb_name=0, max_inst_name=0; |
| |
| m_tracing = 0; //don't allow tracing during display |
| |
| if(m_typename != "") tname = m_typename; |
| else if(obj != null) tname = obj.get_type_name(); |
| else tname = "*"; |
| |
| q = m_t_inst.m_tw_cb_q; |
| for(int i=0; i<q.size(); ++i) begin |
| cb = q.get(i); |
| cbq.push_back(cb.get_name()); |
| inst_q.push_back("(*)"); |
| if(cb.is_enabled()) mode_q.push_back("ON"); |
| else mode_q.push_back("OFF"); |
| |
| str = cb.get_name(); |
| max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len(); |
| str = "(*)"; |
| max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); |
| end |
| |
| if(obj ==null) begin |
| if(m_t_inst.m_pool.first(bobj)) begin |
| do |
| if($cast(me,bobj)) break; |
| while(m_t_inst.m_pool.next(bobj)); |
| end |
| if(me != null || m_t_inst.m_tw_cb_q.size()) begin |
| qs.push_back($sformatf("Registered callbacks for all instances of %s\n", tname)); |
| qs.push_back("---------------------------------------------------------------\n"); |
| end |
| if(me != null) begin |
| do begin |
| if($cast(me,bobj)) begin |
| q = m_t_inst.m_pool.get(bobj); |
| if (q==null) begin |
| q=new; |
| m_t_inst.m_pool.add(bobj,q); |
| end |
| for(int i=0; i<q.size(); ++i) begin |
| cb = q.get(i); |
| cbq.push_back(cb.get_name()); |
| inst_q.push_back(bobj.get_full_name()); |
| if(cb.is_enabled()) mode_q.push_back("ON"); |
| else mode_q.push_back("OFF"); |
| |
| str = cb.get_name(); |
| max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len(); |
| str = bobj.get_full_name(); |
| max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); |
| end |
| end |
| end while (m_t_inst.m_pool.next(bobj)); |
| end |
| else begin |
| qs.push_back($sformatf("No callbacks registered for any instances of type %s\n", tname)); |
| end |
| end |
| else begin |
| if(m_t_inst.m_pool.exists(bobj) || m_t_inst.m_tw_cb_q.size()) begin |
| qs.push_back($sformatf("Registered callbacks for instance %s of %s\n", obj.get_full_name(), tname)); |
| qs.push_back("---------------------------------------------------------------\n"); |
| end |
| if(m_t_inst.m_pool.exists(bobj)) begin |
| q = m_t_inst.m_pool.get(bobj); |
| if(q==null) begin |
| q=new; |
| m_t_inst.m_pool.add(bobj,q); |
| end |
| for(int i=0; i<q.size(); ++i) begin |
| cb = q.get(i); |
| cbq.push_back(cb.get_name()); |
| inst_q.push_back(bobj.get_full_name()); |
| if(cb.is_enabled()) mode_q.push_back("ON"); |
| else mode_q.push_back("OFF"); |
| |
| str = cb.get_name(); |
| max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len(); |
| str = bobj.get_full_name(); |
| max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); |
| end |
| end |
| end |
| if(!cbq.size()) begin |
| if(obj == null) str = "*"; |
| else str = obj.get_full_name(); |
| qs.push_back($sformatf("No callbacks registered for instance %s of type %s\n", str, tname)); |
| end |
| |
| foreach (cbq[i]) begin |
| qs.push_back($sformatf("%s %s %s on %s %s\n", cbq[i], blanks.substr(0,max_cb_name-cbq[i].len()-1), inst_q[i], blanks.substr(0,max_inst_name - inst_q[i].len()-1), mode_q[i])); |
| end |
| `uvm_info("UVM/CB/DISPLAY",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE) |
| |
| m_tracing = 1; //allow tracing to be resumed |
| endfunction |
| |
| endclass |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| // |
| // CLASS: uvm_callbacks #(T,CB) |
| // |
| // The ~uvm_callbacks~ class provides a base class for implementing callbacks, |
| // which are typically used to modify or augment component behavior without |
| // changing the component class. To work effectively, the developer of the |
| // component class defines a set of "hook" methods that enable users to |
| // customize certain behaviors of the component in a manner that is controlled |
| // by the component developer. The integrity of the component's overall behavior |
| // is intact, while still allowing certain customizable actions by the user. |
| // |
| // To enable compile-time type-safety, the class is parameterized on both the |
| // user-defined callback interface implementation as well as the object type |
| // associated with the callback. The object type-callback type pair are |
| // associated together using the <`uvm_register_cb> macro to define |
| // a valid pairing; valid pairings are checked when a user attempts to add |
| // a callback to an object. |
| // |
| // To provide the most flexibility for end-user customization and reuse, it |
| // is recommended that the component developer also define a corresponding set |
| // of virtual method hooks in the component itself. This affords users the ability |
| // to customize via inheritance/factory overrides as well as callback object |
| // registration. The implementation of each virtual method would provide the |
| // default traversal algorithm for the particular callback being called. Being |
| // virtual, users can define subtypes that override the default algorithm, |
| // perform tasks before and/or after calling super.<method> to execute any |
| // registered callbacks, or to not call the base implementation, effectively |
| // disabling that particular hook. A demonstration of this methodology is |
| // provided in an example included in the kit. |
| //------------------------------------------------------------------------------ |
| |
| class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) |
| extends uvm_typed_callbacks#(T); |
| |
| // Parameter: T |
| // |
| // This type parameter specifies the base object type with which the |
| // <CB> callback objects will be registered. This object must be |
| // a derivative of ~uvm_object~. |
| |
| // Parameter: CB |
| // |
| // This type parameter specifies the base callback type that will be |
| // managed by this callback class. The callback type is typically a |
| // interface class, which defines one or more virtual method prototypes |
| // that users can override in subtypes. This type must be a derivative |
| // of <uvm_callback>. |
| |
| typedef uvm_typed_callbacks#(T) super_type; |
| typedef uvm_callbacks#(T,CB) this_type; |
| |
| |
| // Singleton instance is used for type checking |
| local static this_type m_inst; |
| |
| // typeinfo |
| static uvm_typeid_base m_typeid; |
| static uvm_typeid_base m_cb_typeid; |
| |
| static string m_typename; |
| static string m_cb_typename; |
| static uvm_report_object reporter = new("cb_tracer"); |
| static uvm_callbacks#(T,uvm_callback) m_base_inst; |
| |
| bit m_registered; |
| |
| // get |
| // --- |
| |
| static function this_type get(); |
| |
| if (m_inst == null) begin |
| uvm_typeid_base cb_base_type; |
| |
| void'(super_type::m_initialize()); |
| |
| cb_base_type = uvm_typeid#(uvm_callback)::get(); |
| m_cb_typeid = uvm_typeid#(CB)::get(); |
| m_typeid = uvm_typeid#(T)::get(); |
| |
| m_inst = new; |
| |
| if (cb_base_type == m_cb_typeid) begin |
| $cast(m_base_inst, m_inst); |
| // The base inst in the super class gets set to this base inst |
| m_t_inst = m_base_inst; |
| uvm_typeid_base::typeid_map[m_typeid] = m_inst; |
| uvm_typeid_base::type_map[m_b_inst] = m_typeid; |
| end |
| else begin |
| m_base_inst = uvm_callbacks#(T,uvm_callback)::get(); |
| m_base_inst.m_this_type.push_back(m_inst); |
| end |
| |
| if (m_inst == null) |
| `uvm_fatal("CB/INTERNAL","get(): m_inst is null") |
| end |
| |
| return m_inst; |
| endfunction |
| |
| |
| |
| // m_register_pair |
| // ------------- |
| // Register valid callback type |
| |
| static function bit m_register_pair(string tname="", cbname=""); |
| this_type inst = get(); |
| |
| m_typename = tname; |
| super_type::m_typename = tname; |
| m_typeid.typename = tname; |
| |
| m_cb_typename = cbname; |
| m_cb_typeid.typename = cbname; |
| |
| inst.m_registered = 1; |
| |
| return 1; |
| endfunction |
| |
| virtual function bit m_is_registered(uvm_object obj, uvm_callback cb); |
| if(m_is_for_me(cb) && m_am_i_a(obj)) begin |
| return m_registered; |
| end |
| endfunction |
| |
| //Does type check to see if the callback is valid for this type |
| virtual function bit m_is_for_me(uvm_callback cb); |
| CB this_cb; |
| return($cast(this_cb,cb)); |
| endfunction |
| |
| // Group: Add/delete interface |
| |
| // Function: add |
| // |
| // Registers the given callback object, ~cb~, with the given |
| // ~obj~ handle. The ~obj~ handle can be ~null~, which allows |
| // registration of callbacks without an object context. If |
| // ~ordering~ is UVM_APPEND (default), the callback will be executed |
| // after previously added callbacks, else the callback |
| // will be executed ahead of previously added callbacks. The ~cb~ |
| // is the callback handle; it must be non-~null~, and if the callback |
| // has already been added to the object instance then a warning is |
| // issued. Note that the CB parameter is optional. For example, the |
| // following are equivalent: |
| // |
| //| uvm_callbacks#(my_comp)::add(comp_a, cb); |
| //| uvm_callbacks#(my_comp, my_callback)::add(comp_a,cb); |
| |
| static function void add(T obj, uvm_callback cb, uvm_apprepend ordering=UVM_APPEND); |
| uvm_queue#(uvm_callback) q; |
| string nm,tnm; |
| |
| void'(get()); |
| |
| if (cb==null) begin |
| if (obj==null) |
| nm = "(*)"; |
| else |
| nm = obj.get_full_name(); |
| |
| if (m_base_inst.m_typename!="") |
| tnm = m_base_inst.m_typename; |
| else if (obj != null) |
| tnm = obj.get_type_name(); |
| else |
| tnm = "uvm_object"; |
| |
| uvm_report_error("CBUNREG", |
| {"Null callback object cannot be registered with object ", |
| nm, " (", tnm, ")"}, UVM_NONE); |
| return; |
| end |
| |
| if (!m_base_inst.check_registration(obj,cb)) begin |
| |
| if (obj==null) |
| nm = "(*)"; |
| else |
| nm = obj.get_full_name(); |
| |
| if (m_base_inst.m_typename!="") |
| tnm = m_base_inst.m_typename; |
| else if(obj != null) |
| tnm = obj.get_type_name(); |
| else |
| tnm = "uvm_object"; |
| |
| uvm_report_warning("CBUNREG", |
| {"Callback ", cb.get_name(), " cannot be registered with object ", |
| nm, " because callback type ", cb.get_type_name(), |
| " is not registered with object type ", tnm }, UVM_NONE); |
| end |
| |
| if(obj == null) begin |
| |
| if (m_cb_find(m_t_inst.m_tw_cb_q,cb) != -1) begin |
| |
| if (m_base_inst.m_typename!="") |
| tnm = m_base_inst.m_typename; |
| else tnm = "uvm_object"; |
| |
| uvm_report_warning("CBPREG", |
| {"Callback object ", cb.get_name(), |
| " is already registered with type ", tnm }, UVM_NONE); |
| end |
| else begin |
| `uvm_cb_trace_noobj(cb,$sformatf("Add (%s) typewide callback %0s for type %s", |
| ordering.name(), cb.get_name(), m_base_inst.m_typename)) |
| m_t_inst.m_add_tw_cbs(cb,ordering); |
| end |
| end |
| |
| else begin |
| |
| `uvm_cb_trace_noobj(cb,$sformatf("Add (%s) callback %0s to object %0s ", |
| ordering.name(), cb.get_name(), obj.get_full_name())) |
| |
| q = m_base_inst.m_pool.get(obj); |
| |
| if (q==null) begin |
| q=new; |
| m_base_inst.m_pool.add(obj,q); |
| end |
| |
| if(q.size() == 0) begin |
| // Need to make sure that registered report catchers are added. This |
| // way users don't need to set up uvm_report_object as a super type. |
| uvm_report_object o; |
| |
| if($cast(o,obj)) begin |
| uvm_queue#(uvm_callback) qr; |
| void'(uvm_callbacks#(uvm_report_object, uvm_callback)::get()); |
| qr = uvm_callbacks#(uvm_report_object,uvm_callback)::m_t_inst.m_tw_cb_q; |
| for(int i=0; i<qr.size(); ++i) |
| q.push_back(qr.get(i)); |
| end |
| |
| for(int i=0; i<m_t_inst.m_tw_cb_q.size(); ++i) |
| q.push_back(m_t_inst.m_tw_cb_q.get(i)); |
| end |
| |
| //check if already exists in the queue |
| if(m_cb_find(q,cb) != -1) begin |
| uvm_report_warning("CBPREG", { "Callback object ", cb.get_name(), " is already registered", |
| " with object ", obj.get_full_name() }, UVM_NONE); |
| end |
| else begin |
| void'(m_cb_find_name(q, cb.get_name(), {"object instance ", obj.get_full_name()})); |
| if(ordering == UVM_APPEND) |
| q.push_back(cb); |
| else |
| q.push_front(cb); |
| end |
| end |
| endfunction |
| |
| // Function: add_by_name |
| // |
| // Registers the given callback object, ~cb~, with one or more uvm_components. |
| // The components must already exist and must be type T or a derivative. As |
| // with <add> the CB parameter is optional. ~root~ specifies the location in |
| // the component hierarchy to start the search for ~name~. See <uvm_root::find_all> |
| // for more details on searching by name. |
| |
| static function void add_by_name(string name, |
| uvm_callback cb, |
| uvm_component root, |
| uvm_apprepend ordering=UVM_APPEND); |
| uvm_component cq[$]; |
| uvm_root top; |
| uvm_coreservice_t cs; |
| T t; |
| void'(get()); |
| cs = uvm_coreservice_t::get(); |
| top = cs.get_root(); |
| |
| if(cb==null) begin |
| uvm_report_error("CBUNREG", { "Null callback object cannot be registered with object(s) ", |
| name }, UVM_NONE); |
| return; |
| end |
| `uvm_cb_trace_noobj(cb,$sformatf("Add (%s) callback %0s by name to object(s) %0s ", |
| ordering.name(), cb.get_name(), name)) |
| top.find_all(name,cq,root); |
| if(cq.size() == 0) begin |
| uvm_report_warning("CBNOMTC", { "add_by_name failed to find any components matching the name ", |
| name, ", callback ", cb.get_name(), " will not be registered." }, UVM_NONE); |
| end |
| foreach(cq[i]) begin |
| if($cast(t,cq[i])) begin |
| add(t,cb,ordering); |
| end |
| end |
| endfunction |
| |
| |
| // Function: delete |
| // |
| // Deletes the given callback object, ~cb~, from the queue associated with |
| // the given ~obj~ handle. The ~obj~ handle can be ~null~, which allows |
| // de-registration of callbacks without an object context. |
| // The ~cb~ is the callback handle; it must be non-~null~, and if the callback |
| // has already been removed from the object instance then a warning is |
| // issued. Note that the CB parameter is optional. For example, the |
| // following are equivalent: |
| // |
| //| uvm_callbacks#(my_comp)::delete(comp_a, cb); |
| //| uvm_callbacks#(my_comp, my_callback)::delete(comp_a,cb); |
| |
| static function void delete(T obj, uvm_callback cb); |
| uvm_object b_obj = obj; |
| uvm_queue#(uvm_callback) q; |
| bit found; |
| int pos; |
| void'(get()); |
| |
| if(obj == null) begin |
| `uvm_cb_trace_noobj(cb,$sformatf("Delete typewide callback %0s for type %s", |
| cb.get_name(), m_base_inst.m_typename)) |
| found = m_t_inst.m_delete_tw_cbs(cb); |
| end |
| else begin |
| `uvm_cb_trace_noobj(cb,$sformatf("Delete callback %0s from object %0s ", |
| cb.get_name(), obj.get_full_name())) |
| q = m_base_inst.m_pool.get(b_obj); |
| pos = m_cb_find(q,cb); |
| if(pos != -1) begin |
| q.delete(pos); |
| found = 1; |
| end |
| end |
| if(!found) begin |
| string nm; |
| if(obj==null) nm = "(*)"; else nm = obj.get_full_name(); |
| uvm_report_warning("CBUNREG", { "Callback ", cb.get_name(), " cannot be removed from object ", |
| nm, " because it is not currently registered to that object." }, UVM_NONE); |
| end |
| endfunction |
| |
| |
| // Function: delete_by_name |
| // |
| // Removes the given callback object, ~cb~, associated with one or more |
| // uvm_component callback queues. As with <delete> the CB parameter is |
| // optional. ~root~ specifies the location in the component hierarchy to start |
| // the search for ~name~. See <uvm_root::find_all> for more details on searching |
| // by name. |
| |
| static function void delete_by_name(string name, uvm_callback cb, |
| uvm_component root); |
| uvm_component cq[$]; |
| uvm_root top; |
| T t; |
| uvm_coreservice_t cs; |
| void'(get()); |
| cs = uvm_coreservice_t::get(); |
| top = cs.get_root(); |
| |
| `uvm_cb_trace_noobj(cb,$sformatf("Delete callback %0s by name from object(s) %0s ", |
| cb.get_name(), name)) |
| top.find_all(name,cq,root); |
| if(cq.size() == 0) begin |
| uvm_report_warning("CBNOMTC", { "delete_by_name failed to find any components matching the name ", |
| name, ", callback ", cb.get_name(), " will not be unregistered." }, UVM_NONE); |
| end |
| foreach(cq[i]) begin |
| if($cast(t,cq[i])) begin |
| delete(t,cb); |
| end |
| end |
| endfunction |
| |
| |
| //-------------------------- |
| // Group: Iterator Interface |
| //-------------------------- |
| // |
| // This set of functions provide an iterator interface for callback queues. A facade |
| // class, <uvm_callback_iter> is also available, and is the generally preferred way to |
| // iterate over callback queues. |
| |
| static function void m_get_q (ref uvm_queue #(uvm_callback) q, input T obj); |
| if(!m_base_inst.m_pool.exists(obj)) begin //no instance specific |
| q = (obj == null) ? m_t_inst.m_tw_cb_q : m_t_inst.m_get_tw_cb_q(obj); |
| end |
| else begin |
| q = m_base_inst.m_pool.get(obj); |
| if(q==null) begin |
| q=new; |
| m_base_inst.m_pool.add(obj,q); |
| end |
| end |
| endfunction |
| |
| |
| // Function: get_first |
| // |
| // Returns the first enabled callback of type CB which resides in the queue for ~obj~. |
| // If ~obj~ is ~null~ then the typewide queue for T is searched. ~itr~ is the iterator; |
| // it will be updated with a value that can be supplied to <get_next> to get the next |
| // callback object. |
| // |
| // If the queue is empty then ~null~ is returned. |
| // |
| // The iterator class <uvm_callback_iter> may be used as an alternative, simplified, |
| // iterator interface. |
| |
| static function CB get_first (ref int itr, input T obj); |
| uvm_queue#(uvm_callback) q; |
| CB cb; |
| void'(get()); |
| m_get_q(q,obj); |
| for(itr = 0; itr<q.size(); ++itr) |
| if($cast(cb, q.get(itr)) && cb.callback_mode()) |
| return cb; |
| return null; |
| endfunction |
| |
| // Function: get_last |
| // |
| // Returns the last enabled callback of type CB which resides in the queue for ~obj~. |
| // If ~obj~ is ~null~ then the typewide queue for T is searched. ~itr~ is the iterator; |
| // it will be updated with a value that can be supplied to <get_prev> to get the previous |
| // callback object. |
| // |
| // If the queue is empty then ~null~ is returned. |
| // |
| // The iterator class <uvm_callback_iter> may be used as an alternative, simplified, |
| // iterator interface. |
| |
| static function CB get_last (ref int itr, input T obj); |
| uvm_queue#(uvm_callback) q; |
| CB cb; |
| void'(get()); |
| m_get_q(q,obj); |
| for(itr = q.size()-1; itr>=0; --itr) |
| if ($cast(cb, q.get(itr)) && cb.callback_mode()) |
| return cb; |
| return null; |
| endfunction |
| |
| |
| // Function: get_next |
| // |
| // Returns the next enabled callback of type CB which resides in the queue for ~obj~, |
| // using ~itr~ as the starting point. If ~obj~ is ~null~ then the typewide queue for T |
| // is searched. ~itr~ is the iterator; it will be updated with a value that can be |
| // supplied to <get_next> to get the next callback object. |
| // |
| // If no more callbacks exist in the queue, then ~null~ is returned. <get_next> will |
| // continue to return ~null~ in this case until <get_first> or <get_last> has been used to reset |
| // the iterator. |
| // |
| // The iterator class <uvm_callback_iter> may be used as an alternative, simplified, |
| // iterator interface. |
| |
| static function CB get_next (ref int itr, input T obj); |
| uvm_queue#(uvm_callback) q; |
| CB cb; |
| void'(get()); |
| m_get_q(q,obj); |
| for(itr = itr+1; itr<q.size(); ++itr) |
| if ($cast(cb, q.get(itr)) && cb.callback_mode()) |
| return cb; |
| return null; |
| endfunction |
| |
| |
| // Function: get_prev |
| // |
| // Returns the previous enabled callback of type CB which resides in the queue for ~obj~, |
| // using ~itr~ as the starting point. If ~obj~ is ~null~ then the typewide queue for T |
| // is searched. ~itr~ is the iterator; it will be updated with a value that can be |
| // supplied to <get_prev> to get the previous callback object. |
| // |
| // If no more callbacks exist in the queue, then ~null~ is returned. <get_prev> will |
| // continue to return ~null~ in this case until <get_first> or <get_last> has been used to reset |
| // the iterator. |
| // |
| // The iterator class <uvm_callback_iter> may be used as an alternative, simplified, |
| // iterator interface. |
| |
| static function CB get_prev (ref int itr, input T obj); |
| uvm_queue#(uvm_callback) q; |
| CB cb; |
| void'(get()); |
| m_get_q(q,obj); |
| for(itr = itr-1; itr>= 0; --itr) |
| if($cast(cb, q.get(itr)) && cb.callback_mode()) |
| return cb; |
| return null; |
| endfunction |
| |
| |
| //------------- |
| // Group: Debug |
| //------------- |
| |
| // Function: display |
| // |
| // This function displays callback information for ~obj~. If ~obj~ is |
| // ~null~, then it displays callback information for all objects |
| // of type ~T~, including typewide callbacks. |
| |
| static function void display(T obj=null); |
| // For documentation purposes, need a function wrapper here. |
| void'(get()); |
| super_type::display(obj); |
| endfunction |
| |
| endclass |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Class- uvm_derived_callbacks #(T,ST,CB) |
| // |
| //------------------------------------------------------------------------------ |
| // This type is not really expected to be used directly by the user, instead they are |
| // expected to use the macro `uvm_set_super_type. The sole purpose of this type is to |
| // allow for setting up of the derived_type/super_type mapping. |
| //------------------------------------------------------------------------------ |
| |
| class uvm_derived_callbacks#(type T=uvm_object, type ST=uvm_object, type CB=uvm_callback) |
| extends uvm_callbacks#(T,CB); |
| |
| typedef uvm_derived_callbacks#(T,ST,CB) this_type; |
| typedef uvm_callbacks#(T) this_user_type; |
| typedef uvm_callbacks#(ST) this_super_type; |
| |
| // Singleton instance is used for type checking |
| static this_type m_d_inst; |
| static this_user_type m_user_inst; |
| static this_super_type m_super_inst; |
| |
| // typeinfo |
| static uvm_typeid_base m_s_typeid; |
| |
| static function this_type get(); |
| m_user_inst = this_user_type::get(); |
| m_super_inst = this_super_type::get(); |
| m_s_typeid = uvm_typeid#(ST)::get(); |
| if(m_d_inst == null) begin |
| m_d_inst = new; |
| end |
| return m_d_inst; |
| endfunction |
| |
| static function bit register_super_type(string tname="", sname=""); |
| this_user_type u_inst = this_user_type::get(); |
| this_type inst = this_type::get(); |
| uvm_callbacks_base s_obj; |
| |
| this_user_type::m_t_inst.m_typename = tname; |
| |
| if(sname != "") m_s_typeid.typename = sname; |
| |
| if(u_inst.m_super_type != null) begin |
| if(u_inst.m_super_type == m_s_typeid) return 1; |
| uvm_report_warning("CBTPREG", { "Type ", tname, " is already registered to super type ", |
| this_super_type::m_t_inst.m_typename, ". Ignoring attempt to register to super type ", |
| sname}, UVM_NONE); |
| return 1; |
| end |
| if(this_super_type::m_t_inst.m_typename == "") |
| this_super_type::m_t_inst.m_typename = sname; |
| u_inst.m_super_type = m_s_typeid; |
| u_inst.m_base_inst.m_super_type = m_s_typeid; |
| s_obj = uvm_typeid_base::typeid_map[m_s_typeid]; |
| s_obj.m_derived_types.push_back(m_typeid); |
| return 1; |
| endfunction |
| |
| endclass |
| |
| |
| //------------------------------------------------------------------------------ |
| // |
| // CLASS: uvm_callback_iter |
| // |
| //------------------------------------------------------------------------------ |
| // The ~uvm_callback_iter~ class is an iterator class for iterating over |
| // callback queues of a specific callback type. The typical usage of |
| // the class is: |
| // |
| //| uvm_callback_iter#(mycomp,mycb) iter = new(this); |
| //| for(mycb cb = iter.first(); cb != null; cb = iter.next()) |
| //| cb.dosomething(); |
| // |
| // The callback iteration macros, <`uvm_do_callbacks> and |
| // <`uvm_do_callbacks_exit_on> provide a simple method for iterating |
| // callbacks and executing the callback methods. |
| //------------------------------------------------------------------------------ |
| |
| class uvm_callback_iter#(type T = uvm_object, type CB = uvm_callback); |
| |
| local int m_i; |
| local T m_obj; |
| local CB m_cb; |
| |
| // Function: new |
| // |
| // Creates a new callback iterator object. It is required that the object |
| // context be provided. |
| |
| function new(T obj); |
| m_obj = obj; |
| endfunction |
| |
| // Function: first |
| // |
| // Returns the first valid (enabled) callback of the callback type (or |
| // a derivative) that is in the queue of the context object. If the |
| // queue is empty then ~null~ is returned. |
| |
| function CB first(); |
| m_cb = uvm_callbacks#(T,CB)::get_first(m_i, m_obj); |
| return m_cb; |
| endfunction |
| |
| // Function: last |
| // |
| // Returns the last valid (enabled) callback of the callback type (or |
| // a derivative) that is in the queue of the context object. If the |
| // queue is empty then ~null~ is returned. |
| |
| function CB last(); |
| m_cb = uvm_callbacks#(T,CB)::get_last(m_i, m_obj); |
| return m_cb; |
| endfunction |
| |
| // Function: next |
| // |
| // Returns the next valid (enabled) callback of the callback type (or |
| // a derivative) that is in the queue of the context object. If there |
| // are no more valid callbacks in the queue, then ~null~ is returned. |
| |
| function CB next(); |
| m_cb = uvm_callbacks#(T,CB)::get_next(m_i, m_obj); |
| return m_cb; |
| endfunction |
| |
| // Function: prev |
| // |
| // Returns the previous valid (enabled) callback of the callback type (or |
| // a derivative) that is in the queue of the context object. If there |
| // are no more valid callbacks in the queue, then ~null~ is returned. |
| |
| function CB prev(); |
| m_cb = uvm_callbacks#(T,CB)::get_prev(m_i, m_obj); |
| return m_cb; |
| endfunction |
| |
| // Function: get_cb |
| // |
| // Returns the last callback accessed via a first() or next() |
| // call. |
| |
| function CB get_cb(); |
| return m_cb; |
| endfunction |
| |
| /**** |
| function void trace(uvm_object obj = null); |
| if (m_cb != null && T::cbs::get_debug_flags() & UVM_CALLBACK_TRACE) begin |
| uvm_report_object reporter = null; |
| string who = "Executing "; |
| void'($cast(reporter, obj)); |
| if (reporter == null) void'($cast(reporter, m_obj)); |
| if (reporter == null) reporter = uvm_top; |
| if (obj != null) who = {obj.get_full_name(), " is executing "}; |
| else if (m_obj != null) who = {m_obj.get_full_name(), " is executing "}; |
| reporter.uvm_report_info("CLLBK_TRC", {who, "callback ", m_cb.get_name()}, UVM_LOW); |
| end |
| endfunction |
| ****/ |
| endclass |
| |
| |
| |
| //------------------------------------------------------------------------------ |
| // CLASS: uvm_callback |
| // |
| // The ~uvm_callback~ class is the base class for user-defined callback classes. |
| // Typically, the component developer defines an application-specific callback |
| // class that extends from this class. In it, he defines one or more virtual |
| // methods, called a ~callback interface~, that represent the hooks available |
| // for user override. |
| // |
| // Methods intended for optional override should not be declared ~pure.~ Usually, |
| // all the callback methods are defined with empty implementations so users have |
| // the option of overriding any or all of them. |
| // |
| // The prototypes for each hook method are completely application specific with |
| // no restrictions. |
| //------------------------------------------------------------------------------ |
| |
| class uvm_callback extends uvm_object; |
| |
| static uvm_report_object reporter = new("cb_tracer"); |
| |
| protected bit m_enabled = 1; |
| |
| // Function: new |
| // |
| // Creates a new uvm_callback object, giving it an optional ~name~. |
| |
| function new(string name="uvm_callback"); |
| super.new(name); |
| endfunction |
| |
| |
| // Function: callback_mode |
| // |
| // Enable/disable callbacks (modeled like rand_mode and constraint_mode). |
| |
| function bit callback_mode(int on=-1); |
| if(on == 0 || on == 1) begin |
| `uvm_cb_trace_noobj(this,$sformatf("Setting callback mode for %s to %s", |
| get_name(), ((on==1) ? "ENABLED":"DISABLED"))) |
| end |
| else begin |
| `uvm_cb_trace_noobj(this,$sformatf("Callback mode for %s is %s", |
| get_name(), ((m_enabled==1) ? "ENABLED":"DISABLED"))) |
| end |
| callback_mode = m_enabled; |
| if(on==0) m_enabled=0; |
| if(on==1) m_enabled=1; |
| endfunction |
| |
| |
| // Function: is_enabled |
| // |
| // Returns 1 if the callback is enabled, 0 otherwise. |
| |
| function bit is_enabled(); |
| return callback_mode(); |
| endfunction |
| |
| static string type_name = "uvm_callback"; |
| |
| |
| // Function: get_type_name |
| // |
| // Returns the type name of this callback object. |
| |
| virtual function string get_type_name(); |
| return type_name; |
| endfunction |
| |
| endclass |
| |
| |
| `endif // UVM_CALLBACK_SVH |
| |
| |