//----------------------------------------------------------------------
// 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 [docs]uvm_root;
typedef class [docs]uvm_callback;
typedef class [docs]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 [docs]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 [docs]uvm_typeid#(type T=uvm_object) extends uvm_typeid_base;
static uvm_typeid#(T) m_b_inst;
static function uvm_typeid#(T) [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]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 [docs]new(string name="uvm_callback");
super.new(name);
endfunction
// Function: callback_mode
//
// Enable/disable callbacks (modeled like rand_mode and constraint_mode).
function bit [docs]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 [docs]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 [docs]get_type_name();
return type_name;
endfunction
endclass
`endif // UVM_CALLBACK_SVH