#-----------------------------------------------------------------------------
# Copyright 2007-2011 Mentor Graphics Corporation
# Copyright 2007-2011 Cadence Design Systems, Inc.
# Copyright 2010 Synopsys, Inc.
# Copyright 2019-2020 Tuomas Poikela (tpoikela)
# 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.
#-----------------------------------------------------------------------------
from ..base.uvm_debug import uvm_debug
from ..base.uvm_globals import UVM_NONE, uvm_report_info
from ..base.sv import sv
#//-----------------------------------------------------------------------------
#// Title: Callback Macros
#//
#// These macros are used to register and execute callbacks extending
#// from ~uvm_callbacks~.
#//-----------------------------------------------------------------------------
#//-----------------------------------------------------------------------------
#// MACRO: `uvm_register_cb
#//
#//| `uvm_register_cb(T,CB)
#//
#// Registers the given ~CB~ callback type with the given ~T~ object type. If
#// a type-callback pair is not registered then a warning is issued if an
#// attempt is made to use the pair (add, delete, etc.).
#//
#// The registration will typically occur in the component that executes the
#// given type of callback. For instance:
#//
#//| virtual class mycb extends uvm_callback;
#//| virtual function void doit();
#//| endclass
#//|
#//| class my_comp extends uvm_component;
#//| `uvm_register_cb(my_comp,mycb)
#//| ...
#//| task run_phase(uvm_phase phase);
#//| ...
#//| `uvm_do_callbacks(my_comp, mycb, doit())
#//| endtask
#//| endclass
#//-----------------------------------------------------------------------------
#`define uvm_register_cb(T,CB) \
# static local bit m_register_cb_``CB = uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`");
[docs]def uvm_register_cb(T, CB):
from ..base.uvm_callback import UVMCallbacks
Ts = T.__name__
cb_name = "_m_register_cb_" + CB.__name__
ok = UVMCallbacks.m_register_pair(Ts, CB.__name__, T)
setattr(T, cb_name, ok)
#//-----------------------------------------------------------------------------
#// MACRO: `uvm_set_super_type
#//
#//| `uvm_set_super_type(T,ST)
#//
#// Defines the super type of ~T~ to be ~ST~. This allows for derived class
#// objects to inherit typewide callbacks that are registered with the base
#// class.
#//
#// The registration will typically occur in the component that executes the
#// given type of callback. For instance:
#//
#//| virtual class mycb extend uvm_callback;
#//| virtual function void doit();
#//| endclass
#//|
#//| class my_comp extends uvm_component;
#//| `uvm_register_cb(my_comp,mycb)
#//| ...
#//| task run_phase(uvm_phase phase);
#//| ...
#//| `uvm_do_callbacks(my_comp, mycb, doit())
#//| endtask
#//| endclass
#//|
#//| class my_derived_comp extends my_comp;
#//| `uvm_set_super_type(my_derived_comp,my_comp)
#//| ...
#//| task run_phase(uvm_phase phase);
#//| ...
#//| `uvm_do_callbacks(my_comp, mycb, doit())
#//| endtask
#//| endclass
#//-----------------------------------------------------------------------------
#`define uvm_set_super_type(T,ST) \
# static local bit m_register_``T``ST = uvm_derived_callbacks#(T,ST)::register_super_type(`"T`",`"ST`");
#-----------------------------------------------------------------------------
# MACRO: `uvm_do_callbacks
#
#| `uvm_do_callbacks(T,CB,METHOD)
#
# Calls the given ~METHOD~ of all callbacks of type ~CB~ registered with
# the calling object (i.e. ~this~ object), which is or is based on type ~T~.
#
# This macro executes all of the callbacks associated with the calling
# object (i.e. ~this~ object). The macro takes three arguments:
#
# - CB is the class type of the callback objects to execute. The class
# type must have a function signature that matches the METHOD argument.
#
# - T is the type associated with the callback. Typically, an instance
# of type T is passed as one the arguments in the ~METHOD~ call.
#
# - METHOD is the method call to invoke, with all required arguments as
# if they were invoked directly.
#
# For example, given the following callback class definition:
#
#| virtual class mycb extends uvm_cb;
#| pure function void my_function (mycomp comp, int addr, int data);
#| endclass
#
# A component would invoke the macro as
#
#| task mycomp::run_phase(uvm_phase phase);
#| int curr_addr, curr_data;
#| ...
#| `uvm_do_callbacks(mycb, mycomp, my_function(this, curr_addr, curr_data))
#| ...
#| endtask
#-----------------------------------------------------------------------------
[docs]def uvm_do_callbacks(self, CB, METHOD, *args):
uvm_debug(self, 'uvm_do_callbacks', 'Exec CBs with ' + METHOD)
uvm_do_obj_callbacks(self, CB, METHOD, *args)
[docs]async def uvm_do_callbacks_async(self, CB, METHOD, *args):
uvm_debug(self, 'uvm_do_callbacks', 'Exec CBs with ' + METHOD)
await uvm_do_obj_callbacks_async(self, CB, METHOD, *args)
#-----------------------------------------------------------------------------
# MACRO: `uvm_do_obj_callbacks
#
#| `uvm_do_obj_callbacks(T,CB,OBJ,METHOD)
#
# Calls the given ~METHOD~ of all callbacks based on type ~CB~ registered with
# the given object, ~OBJ~, which is or is based on type ~T~.
#
# This macro is identical to <`uvm_do_callbacks> macro,
# but it has an additional ~OBJ~ argument to allow the specification of an
# external object to associate the callback with. For example, if the
# callbacks are being applied in a sequence, ~OBJ~ could be specified
# as the associated sequencer or parent sequence.
#
#| ...
#| `uvm_do_callbacks(mycb, mycomp, seqr, my_function(seqr, curr_addr, curr_data))
#| ...
#-----------------------------------------------------------------------------
[docs]def uvm_do_obj_callbacks(OBJ, CB, METHOD, *args):
from ..base.uvm_callback import UVMCallbackIter
cb_iter = UVMCallbackIter(OBJ, CB)
cb = cb_iter.first()
while cb is not None:
uvm_cb_trace_noobj(cb, (
"Executing callback method '{}' for callback {} (CB) from {} (T)"
.format(METHOD, cb.get_name(), OBJ.get_full_name())))
m_to_call = getattr(cb, METHOD)
m_to_call(*args)
cb = cb_iter.next()
[docs]async def uvm_do_obj_callbacks_async(OBJ, CB, METHOD, *args):
from ..base.uvm_callback import UVMCallbackIter
cb_iter = UVMCallbackIter(OBJ, CB)
cb = cb_iter.first()
while cb is not None:
uvm_cb_trace_noobj(cb, (
"Executing callback method '{}' for callback {} (CB) from {} (T)"
.format(METHOD, cb.get_name(), OBJ.get_full_name())))
m_to_call = getattr(cb, METHOD)
await m_to_call(*args)
cb = cb_iter.next()
#//-----------------------------------------------------------------------------
#// MACRO: `uvm_do_callbacks_exit_on
#//
#//| `uvm_do_callbacks_exit_on(T,CB,METHOD,VAL)
#//
#// Calls the given ~METHOD~ of all callbacks of type ~CB~ registered with
#// the calling object (i.e. ~this~ object), which is or is based on type ~T~,
#// returning upon the first callback returning the bit value given by ~VAL~.
#//
#// This macro executes all of the callbacks associated with the calling
#// object (i.e. ~this~ object). The macro takes three arguments:
#//
#// - CB is the class type of the callback objects to execute. The class
#// type must have a function signature that matches the METHOD argument.
#//
#// - T is the type associated with the callback. Typically, an instance
#// of type T is passed as one the arguments in the ~METHOD~ call.
#//
#// - METHOD is the method call to invoke, with all required arguments as
#// if they were invoked directly.
#//
#// - VAL, if 1, says return upon the first callback invocation that
#// returns 1. If 0, says return upon the first callback invocation that
#// returns 0.
#//
#// For example, given the following callback class definition:
#//
#//| virtual class mycb extends uvm_cb;
#//| pure function bit drop_trans (mycomp comp, my_trans trans);
#//| endclass
#//
#// A component would invoke the macro as
#//
#//| task mycomp::run_phase(uvm_phase phase);
#//| my_trans trans;
#//| forever begin
#//| get_port.get(trans);
#//| if(do_callbacks(trans) == 0)
#//| uvm_report_info("DROPPED",{"trans dropped: %s",trans.convert2string()});
#//| else
#//| // execute transaction
#//| end
#//| endtask
#//| function bit do_callbacks(my_trans);
#//| // Returns 0 if drop happens and 1 otherwise
#//| `uvm_do_callbacks_exit_on(mycomp, mycb, extobj, drop_trans(this,trans), 1)
#//| endfunction
#//
#// Because this macro calls ~return~, its use is restricted to implementations
#// of functions that return a ~bit~ value, as in the above example.
#//
#//-----------------------------------------------------------------------------
#`define uvm_do_callbacks_exit_on(T,CB,METHOD,VAL) \
# `uvm_do_obj_callbacks_exit_on(T,CB,this,METHOD,VAL) \
[docs]def uvm_do_callbacks_exit_on(self,CB,METHOD,VAL, *args):
uvm_do_obj_callbacks_exit_on(self, CB, METHOD, VAL, *args)
#//-----------------------------------------------------------------------------
#// MACRO: `uvm_do_obj_callbacks_exit_on
#//
#//| `uvm_do_obj_callbacks_exit_on(T,CB,OBJ,METHOD,VAL)
#//
#// Calls the given ~METHOD~ of all callbacks of type ~CB~ registered with
#// the given object ~OBJ~, which must be or be based on type ~T~, and returns
#// upon the first callback that returns the bit value given by ~VAL~. It is
#// exactly the same as the <`uvm_do_callbacks_exit_on> but has a specific
#// object instance (instead of the implicit this instance) as the third
#// argument.
#//
#//| ...
#//| // Exit if a callback returns a 1
#//| `uvm_do_callbacks_exit_on(mycomp, mycb, seqr, drop_trans(seqr,trans), 1)
#//| ...
#//
#// Because this macro calls ~return~, its use is restricted to implementations
#// of functions that return a ~bit~ value, as in the above example.
#//-----------------------------------------------------------------------------
#`define uvm_do_obj_callbacks_exit_on(T,CB,OBJ,METHOD,VAL) \
# begin \
# uvm_callback_iter#(T,CB) iter = new(OBJ); \
# CB cb = iter.first(); \
# while(cb != null) begin \
# if (cb.METHOD == VAL) begin \
# `uvm_cb_trace_noobj(cb,$sformatf(`"Executed callback method 'METHOD' for callback %s (CB) from %s (T) : returned value VAL (other callbacks will be ignored)`",cb.get_name(), OBJ.get_full_name())) \
# return VAL; \
# end \
# `uvm_cb_trace_noobj(cb,$sformatf(`"Executed callback method 'METHOD' for callback %s (CB) from %s (T) : did not return value VAL`",cb.get_name(), OBJ.get_full_name())) \
# cb = iter.next(); \
# end \
# return 1-VAL; \
# end
[docs]def uvm_do_obj_callbacks_exit_on(OBJ, CB, METHOD, VAL, *args):
from ..base.uvm_callback import UVMCallbackIter
cb_iter = UVMCallbackIter(OBJ, CB)
cb = cb_iter.first()
while cb is not None:
m_to_call = getattr(cb, METHOD)
ret_val = m_to_call(*args)
if ret_val == VAL:
uvm_cb_trace_noobj(cb, sv.sformatf("Executed callback method "
+ "'METHOD' for callback %s (CB) from %s (T) : returned value VAL"
+ "(other callbacks will be ignored)l", cb.get_name(), OBJ.get_full_name()))
return VAL
uvm_cb_trace_noobj(cb, (
"Executed callback method '{}' for callback {} (CB) from {} (T)"
.format(METHOD, cb.get_name(), OBJ.get_full_name())))
cb = cb_iter.next()
return 1-VAL
#// The +define+UVM_CB_TRACE_ON setting will instrument the uvm library to emit
#// messages with message id UVMCB_TRC and UVM_NONE verbosity
#// notifing add,delete and execution of uvm callbacks. The instrumentation is off by default.
#
#`define uvm_cb_trace(OBJ,CB,OPER) \
# begin \
# string msg; \
# msg = (OBJ == null) ? "null" : $sformatf("%s (%s@%0d)", \
# OBJ.get_full_name(), OBJ.get_type_name(), OBJ.get_inst_id()); \
# `uvm_info("UVMCB_TRC", $sformatf("%s: callback %s (%s@%0d) : to object %s", \
# OPER, CB.get_name(), CB.get_type_name(), CB.get_inst_id(), msg), UVM_NONE) \
# end
#
#`define uvm_cb_trace_noobj(CB,OPER) \
# begin \
# if(uvm_callbacks_base::m_tracing) \
# `uvm_info("UVMCB_TRC", $sformatf("%s : callback %s (%s@%0d)" , \
# OPER, CB.get_name(), CB.get_type_name(), CB.get_inst_id()), UVM_NONE) \
# end
[docs]def uvm_cb_trace_noobj(CB, OPER):
from ..base.uvm_callback import UVMCallbacksBase
if UVMCallbacksBase.m_tracing:
uvm_report_info("UVMCB_TRC", ("{} : callback {} ({}@{})".format(
OPER, CB.get_name(), CB.get_type_name(), CB.get_inst_id())), UVM_NONE)