URL
https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk
Subversion Repositories uart2bus_testbench
[/] [uart2bus_testbench/] [trunk/] [tb/] [uvm_src/] [base/] [uvm_objection.svh] - Rev 16
Compare with Previous | Blame | View Log
////----------------------------------------------------------------------// Copyright 2007-2011 Mentor Graphics Corporation// Copyright 2007-2011 Cadence Design Systems, Inc.// Copyright 2010-2011 Synopsys, Inc.// Copyright 2013 NVIDIA Corporation// 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.//----------------------------------------------------------------------`ifndef UVM_OBJECTION_SVH`define UVM_OBJECTION_SVHtypedef class uvm_objection_context_object;typedef class uvm_objection;typedef class uvm_sequence_base;typedef class uvm_objection_callback;typedef uvm_callbacks #(uvm_objection,uvm_objection_callback) uvm_objection_cbs_t;typedef class uvm_cmdline_processor;class uvm_objection_events;int waiters;event raised;event dropped;event all_dropped;endclass//------------------------------------------------------------------------------// Title: Objection Mechanism//------------------------------------------------------------------------------// The following classes define the objection mechanism and end-of-test// functionality, which is based on <uvm_objection>.//------------------------------------------------------------------------------//------------------------------------------------------------------------------//// Class: uvm_objection////------------------------------------------------------------------------------// Objections provide a facility for coordinating status information between// two or more participating components, objects, and even module-based IP.//// Tracing of objection activity can be turned on to follow the activity of// the objection mechanism. It may be turned on for a specific objection// instance with <uvm_objection::trace_mode>, or it can be set for all// objections from the command line using the option +UVM_OBJECTION_TRACE.//------------------------------------------------------------------------------class uvm_objection extends uvm_report_object;`uvm_register_cb(uvm_objection, uvm_objection_callback)protected bit m_trace_mode;protected int m_source_count[uvm_object];protected int m_total_count [uvm_object];protected time m_drain_time [uvm_object];protected uvm_objection_events m_events [uvm_object];/*protected*/ bit m_top_all_dropped;protected uvm_root m_top;static uvm_objection m_objections[$];//// Drain Logic// The context pool holds used context objects, so that// they're not constantly being recreated. The maximum// number of contexts in the pool is equal to the maximum// number of simultaneous drains you could have occuring,// both pre and post forks.//// There's the potential for a programmability within the// library to dictate the largest this pool should be allowed// to grow, but that seems like overkill for the time being.local static uvm_objection_context_object m_context_pool[$];// These are the active drain processes, which have been// forked off by the background process. A raise can// use this array to kill a drain.`ifndef UVM_USE_PROCESS_CONTAINERlocal process m_drain_proc[uvm_object];`elselocal process_container_c m_drain_proc[uvm_object];`endif// These are the contexts which have been scheduled for// retrieval by the background process, but which the// background process hasn't seen yet.local static uvm_objection_context_object m_scheduled_list[$];// Once a context is seen by the background process, it is// removed from the scheduled list, and placed in the forked// list. At the same time, it is placed in the scheduled// contexts array. A re-raise can use the scheduled contexts// array to detect (and cancel) the drain.local uvm_objection_context_object m_scheduled_contexts[uvm_object];local uvm_objection_context_object m_forked_list[$];// Once the forked drain has actually started (this occurs// ~1 delta AFTER the background process schedules it), the// context is removed from the above array and list, and placed// in the forked_contexts list.local uvm_objection_context_object m_forked_contexts[uvm_object];protected bit m_prop_mode = 1;protected bit m_cleared; /* for checking obj count<0 */// Function: new//// Creates a new objection instance. Accesses the command line// argument +UVM_OBJECTION_TRACE to turn tracing on for// all objection objects.function new(string name="");uvm_cmdline_processor clp;uvm_coreservice_t cs_ ;string trace_args[$];super.new(name);cs_ = uvm_coreservice_t::get();m_top = cs_.get_root();set_report_verbosity_level(m_top.get_report_verbosity_level());// Get the command line trace mode settingclp = uvm_cmdline_processor::get_inst();if(clp.get_arg_matches("+UVM_OBJECTION_TRACE", trace_args)) beginm_trace_mode=1;endm_objections.push_back(this);endfunction// Function: trace_mode//// Set or get the trace mode for the objection object. If no// argument is specified (or an argument other than 0 or 1)// the current trace mode is unaffected. A trace_mode of// 0 turns tracing off. A trace mode of 1 turns tracing on.// The return value is the mode prior to being reset.function bit trace_mode (int mode=-1);trace_mode = m_trace_mode;if(mode == 0) m_trace_mode = 0;else if(mode == 1) m_trace_mode = 1;endfunction// Function- m_report//// Internal method for reporting count updatesfunction void m_report(uvm_object obj, uvm_object source_obj, string description, int count, string action);string desc;int _count = m_source_count.exists(obj) ? m_source_count[obj] : 0;int _total = m_total_count.exists(obj) ? m_total_count[obj] : 0;if (!uvm_report_enabled(UVM_NONE,UVM_INFO,"OBJTN_TRC") || !m_trace_mode) return;//desc = description == "" ? "" : {" ", description, "" };if (source_obj == obj)uvm_report_info("OBJTN_TRC",$sformatf("Object %0s %0s %0d objection(s)%s: count=%0d total=%0d",obj.get_full_name()==""?"uvm_top":obj.get_full_name(), action,count, description != ""? {" (",description,")"}:"", _count, _total), UVM_NONE);else beginint cpath = 0, last_dot=0;string sname = source_obj.get_full_name(), nm = obj.get_full_name();int max = sname.len() > nm.len() ? nm.len() : sname.len();// For readability, only print the part of the source obj hierarchy underneath// the current object.while((sname[cpath] == nm[cpath]) && (cpath < max)) beginif(sname[cpath] == ".") last_dot = cpath;cpath++;endif(last_dot) sname = sname.substr(last_dot+1, sname.len());uvm_report_info("OBJTN_TRC",$sformatf("Object %0s %0s %0d objection(s) %0s its total (%s from source object %s%s): count=%0d total=%0d",obj.get_full_name()==""?"uvm_top":obj.get_full_name(), action=="raised"?"added":"subtracted",count, action=="raised"?"to":"from", action, sname,description != ""?{", ",description}:"", _count, _total), UVM_NONE);endendfunction// Function- m_get_parent//// Internal method for getting the parent of the given ~object~.// The ultimate parent is uvm_top, UVM's implicit top-level component.function uvm_object m_get_parent(uvm_object obj);uvm_component comp;uvm_sequence_base seq;if ($cast(comp, obj)) beginobj = comp.get_parent();endelse if ($cast(seq, obj)) beginobj = seq.get_sequencer();endelseobj = m_top;if (obj == null)obj = m_top;return obj;endfunction// Function- m_propagate//// Propagate the objection to the objects parent. If the object is a// component, the parent is just the hierarchical parent. If the object is// a sequence, the parent is the parent sequence if one exists, or// it is the attached sequencer if there is no parent sequence.//// obj : the uvm_object on which the objection is being raised or lowered// source_obj : the root object on which the end user raised/lowered the// objection (as opposed to an anscestor of the end user object)a// count : the number of objections associated with the action.// raise : indicator of whether the objection is being raised or lowered. A// 1 indicates the objection is being raised.function void m_propagate (uvm_object obj,uvm_object source_obj,string description,int count,bit raise,int in_top_thread);if (obj != null && obj != m_top) beginobj = m_get_parent(obj);if(raise)m_raise(obj, source_obj, description, count);elsem_drop(obj, source_obj, description, count, in_top_thread);endendfunction// Group: Objection Control// Function: set_propagate_mode// Sets the propagation mode for this objection.//// By default, objections support hierarchical propagation for// components. For example, if we have the following basic// component tree:////| uvm_top.parent.child//// Any objections raised by 'child' would get propagated// down to parent, and then to uvm_test_top. Resulting in the// following counts and totals:////| | count | total |//| uvm_top.parent.child | 1 | 1 |//| uvm_top.parent | 0 | 1 |//| uvm_top | 0 | 1 |//|//// While propagations such as these can be useful, if they are// unused by the testbench then they are simply an unnecessary// performance hit. If the testbench is not going to use this// functionality, then the performance can be improved by setting// the propagation mode to 0.//// When propagation mode is set to 0, all intermediate callbacks// between the ~source~ and ~top~ will be skipped. This would// result in the following counts and totals for the above objection:////| | count | total |//| uvm_top.parent.child | 1 | 1 |//| uvm_top.parent | 0 | 0 |//| uvm_top | 0 | 1 |//|//// Since the propagation mode changes the behavior of the objection,// it can only be safely changed if there are no objections ~raised~// or ~draining~. Any attempts to change the mode while objections// are ~raised~ or ~draining~ will result in an error.//function void set_propagate_mode (bit prop_mode);if (!m_top_all_dropped && (get_objection_total() != 0)) begin`uvm_error("UVM/BASE/OBJTN/PROP_MODE",{"The propagation mode of '", this.get_full_name(),"' cannot be changed while the objection is raised ","or draining!"})return;endm_prop_mode = prop_mode;endfunction : set_propagate_mode// Function: get_propagate_mode// Returns the propagation mode for this objection.function bit get_propagate_mode();return m_prop_mode;endfunction : get_propagate_mode// Function: raise_objection//// Raises the number of objections for the source ~object~ by ~count~, which// defaults to 1. The ~object~ is usually the ~this~ handle of the caller.// If ~object~ is not specified or ~null~, the implicit top-level component,// <uvm_root>, is chosen.//// Raising an objection causes the following.//// - The source and total objection counts for ~object~ are increased by// ~count~. ~description~ is a string that marks a specific objection// and is used in tracing/debug.//// - The objection's <raised> virtual method is called, which calls the// <uvm_component::raised> method for all of the components up the// hierarchy.//virtual function void raise_objection (uvm_object obj=null,string description="",int count=1);if(obj == null)obj = m_top;m_cleared = 0;m_top_all_dropped = 0;m_raise (obj, obj, description, count);endfunction// Function- m_raisefunction void m_raise (uvm_object obj,uvm_object source_obj,string description="",int count=1);int idx;uvm_objection_context_object ctxt;// Ignore raise if count is 0if (count == 0)return;if (m_total_count.exists(obj))m_total_count[obj] += count;elsem_total_count[obj] = count;if (source_obj==obj) beginif (m_source_count.exists(obj))m_source_count[obj] += count;elsem_source_count[obj] = count;endif (m_trace_mode)m_report(obj,source_obj,description,count,"raised");raised(obj, source_obj, description, count);// Handle any outstanding drains...// First go through the scheduled listidx = 0;while (idx < m_scheduled_list.size()) beginif ((m_scheduled_list[idx].obj == obj) &&(m_scheduled_list[idx].objection == this)) begin// Caught it before the drain was forkedctxt = m_scheduled_list[idx];m_scheduled_list.delete(idx);break;endidx++;end// If it's not there, go through the forked listif (ctxt == null) beginidx = 0;while (idx < m_forked_list.size()) beginif (m_forked_list[idx].obj == obj) begin// Caught it after the drain was forked,// but before the fork startedctxt = m_forked_list[idx];m_forked_list.delete(idx);m_scheduled_contexts.delete(ctxt.obj);break;endidx++;endend// If it's not there, go through the forked contextsif (ctxt == null) beginif (m_forked_contexts.exists(obj)) begin// Caught it with the forked drain runningctxt = m_forked_contexts[obj];m_forked_contexts.delete(obj);// Kill the drain`ifndef UVM_USE_PROCESS_CONTAINERm_drain_proc[obj].kill();m_drain_proc.delete(obj);`elsem_drain_proc[obj].p.kill();m_drain_proc.delete(obj);`endifendendif (ctxt == null) begin// If there were no drains, just propagate as usualif (!m_prop_mode && obj != m_top)m_raise(m_top,source_obj,description,count);else if (obj != m_top)m_propagate(obj, source_obj, description, count, 1, 0);endelse begin// Otherwise we need to determine what exactly happenedint diff_count;// Determine the diff count, if it's positive, then we're// looking at a 'raise' total, if it's negative, then// we're looking at a 'drop', but not down to 0. If it's// a 0, that means that there is no change in the total.diff_count = count - ctxt.count;if (diff_count != 0) begin// Something changedif (diff_count > 0) begin// we're looking at an increase in the totalif (!m_prop_mode && obj != m_top)m_raise(m_top, source_obj, description, diff_count);else if (obj != m_top)m_propagate(obj, source_obj, description, diff_count, 1, 0);endelse begin// we're looking at a decrease in the total// The count field is always positive...diff_count = -diff_count;if (!m_prop_mode && obj != m_top)m_drop(m_top, source_obj, description, diff_count);else if (obj != m_top)m_propagate(obj, source_obj, description, diff_count, 0, 0);endend// Cleanupctxt.clear();m_context_pool.push_back(ctxt);endendfunction// Function: drop_objection//// Drops the number of objections for the source ~object~ by ~count~, which// defaults to 1. The ~object~ is usually the ~this~ handle of the caller.// If ~object~ is not specified or ~null~, the implicit top-level component,// <uvm_root>, is chosen.//// Dropping an objection causes the following.//// - The source and total objection counts for ~object~ are decreased by// ~count~. It is an error to drop the objection count for ~object~ below// zero.//// - The objection's <dropped> virtual method is called, which calls the// <uvm_component::dropped> method for all of the components up the// hierarchy.//// - If the total objection count has not reached zero for ~object~, then// the drop is propagated up the object hierarchy as with// <raise_objection>. Then, each object in the hierarchy will have updated// their ~source~ counts--objections that they originated--and ~total~// counts--the total number of objections by them and all their// descendants.//// If the total objection count reaches zero, propagation up the hierarchy// is deferred until a configurable drain-time has passed and the// <uvm_component::all_dropped> callback for the current hierarchy level// has returned. The following process occurs for each instance up// the hierarchy from the source caller://// A process is forked in a non-blocking fashion, allowing the ~drop~// call to return. The forked process then does the following://// - If a drain time was set for the given ~object~, the process waits for// that amount of time.//// - The objection's <all_dropped> virtual method is called, which calls the// <uvm_component::all_dropped> method (if ~object~ is a component).//// - The process then waits for the ~all_dropped~ callback to complete.//// - After the drain time has elapsed and all_dropped callback has// completed, propagation of the dropped objection to the parent proceeds// as described in <raise_objection>, except as described below.//// If a new objection for this ~object~ or any of its descendants is raised// during the drain time or during execution of the all_dropped callback at// any point, the hierarchical chain described above is terminated and the// dropped callback does not go up the hierarchy. The raised objection will// propagate up the hierarchy, but the number of raised propagated up is// reduced by the number of drops that were pending waiting for the// all_dropped/drain time completion. Thus, if exactly one objection// caused the count to go to zero, and during the drain exactly one new// objection comes in, no raises or drops are propagated up the hierarchy,//// As an optimization, if the ~object~ has no set drain-time and no// registered callbacks, the forked process can be skipped and propagation// proceeds immediately to the parent as described.virtual function void drop_objection (uvm_object obj=null,string description="",int count=1);if(obj == null)obj = m_top;m_drop (obj, obj, description, count, 0);endfunction// Function- m_dropfunction void m_drop (uvm_object obj,uvm_object source_obj,string description="",int count=1,int in_top_thread=0);// Ignore drops if the count is 0if (count == 0)return;if (!m_total_count.exists(obj) || (count > m_total_count[obj])) beginif(m_cleared)return;uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(),"\" attempted to drop objection '",this.get_name(),"' count below zero"});return;endif (obj == source_obj) beginif (!m_source_count.exists(obj) || (count > m_source_count[obj])) beginif(m_cleared)return;uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(),"\" attempted to drop objection '",this.get_name(),"' count below zero"});return;endm_source_count[obj] -= count;endm_total_count[obj] -= count;if (m_trace_mode)m_report(obj,source_obj,description,count,"dropped");dropped(obj, source_obj, description, count);// if count != 0, no reason to forkif (m_total_count[obj] != 0) beginif (!m_prop_mode && obj != m_top)m_drop(m_top,source_obj,description, count, in_top_thread);else if (obj != m_top) beginthis.m_propagate(obj, source_obj, description, count, 0, in_top_thread);endendelse beginuvm_objection_context_object ctxt;if (m_context_pool.size())ctxt = m_context_pool.pop_front();elsectxt = new;ctxt.obj = obj;ctxt.source_obj = source_obj;ctxt.description = description;ctxt.count = count;ctxt.objection = this;// Need to be thread-safe, let the background// process handle it.// Why don't we look at in_top_thread here? Because// a re-raise will kill the drain at object that it's// currently occuring at, and we need the leaf-level kills// to not cause accidental kills at branch-levels in// the propagation.// Using the background process just allows us to// separate the links of the chain.m_scheduled_list.push_back(ctxt);end // else: !if(m_total_count[obj] != 0)endfunction// Function: clear//// Immediately clears the objection state. All counts are cleared and the// any processes waiting on a call to wait_for(UVM_ALL_DROPPED, uvm_top)// are released.//// The caller, if a uvm_object-based object, should pass its 'this' handle// to the ~obj~ argument to document who cleared the objection.// Any drain_times set by the user are not affected.//virtual function void clear(uvm_object obj=null);string name;uvm_objection_context_object ctxt;int idx;if (obj==null)obj=m_top;name = obj.get_full_name();if (name == "")name = "uvm_top";elsename = obj.get_full_name();if (!m_top_all_dropped && get_objection_total(m_top))uvm_report_warning("OBJTN_CLEAR",{"Object '",name,"' cleared objection counts for ",get_name()});//Should there be a warning if there are outstanding objections?m_source_count.delete();m_total_count.delete();// Remove any scheduled drains from the static queueidx = 0;while (idx < m_scheduled_list.size()) beginif (m_scheduled_list[idx].objection == this) beginm_scheduled_list[idx].clear();m_context_pool.push_back(m_scheduled_list[idx]);m_scheduled_list.delete(idx);endelse beginidx++;endend// Scheduled contexts and m_forked_lists have duplicate// entries... clear out one, free the other.m_scheduled_contexts.delete();while (m_forked_list.size()) beginm_forked_list[0].clear();m_context_pool.push_back(m_forked_list[0]);void'(m_forked_list.pop_front());end// running drains have a context and a processforeach (m_forked_contexts[o]) begin`ifndef UVM_USE_PROCESS_CONTAINERm_drain_proc[o].kill();m_drain_proc.delete(o);`elsem_drain_proc[o].p.kill();m_drain_proc.delete(o);`endifm_forked_contexts[o].clear();m_context_pool.push_back(m_forked_contexts[o]);m_forked_contexts.delete(o);endm_top_all_dropped = 0;m_cleared = 1;if (m_events.exists(m_top))->m_events[m_top].all_dropped;endfunction// m_execute_scheduled_forks// -------------------------// background process; when nonstatic task m_execute_scheduled_forks();while(1) beginwait(m_scheduled_list.size() != 0);if(m_scheduled_list.size() != 0) beginuvm_objection_context_object c;uvm_objection o;// Save off the context before the forkc = m_scheduled_list.pop_front();// A re-raise can use this to figure out props (if any)c.objection.m_scheduled_contexts[c.obj] = c;// The fork below pulls out from the forked listc.objection.m_forked_list.push_back(c);// The fork will guard the m_forked_drain call, but// a re-raise can kill m_forked_list contexts in the delta// before the fork executes.fork : guardautomatic uvm_objection objection = c.objection;begin// Check to maike sure re-raise didn't empty the fifoif (objection.m_forked_list.size() > 0) beginuvm_objection_context_object ctxt;ctxt = objection.m_forked_list.pop_front();// Clear it out of scheduledobjection.m_scheduled_contexts.delete(ctxt.obj);// Move it in to forked (so re-raise can figure out props)objection.m_forked_contexts[ctxt.obj] = ctxt;// Save off our process handle, so a re-raise can kill it...`ifndef UVM_USE_PROCESS_CONTAINERobjection.m_drain_proc[ctxt.obj] = process::self();`elsebeginprocess_container_c c = new(process::self());objection.m_drain_proc[ctxt.obj]=c;end`endif// Execute the forked drainobjection.m_forked_drain(ctxt.obj, ctxt.source_obj, ctxt.description, ctxt.count, 1);// Cleanup if we survived (no re-raises)objection.m_drain_proc.delete(ctxt.obj);objection.m_forked_contexts.delete(ctxt.obj);// Clear out the context object (prevent memory leaks)ctxt.clear();// Save the context in the pool for later reusem_context_pool.push_back(ctxt);endendjoin_none : guardendendendtask// m_forked_drain// -------------task m_forked_drain (uvm_object obj,uvm_object source_obj,string description="",int count=1,int in_top_thread=0);int diff_count;if (m_drain_time.exists(obj))`uvm_delay(m_drain_time[obj])if (m_trace_mode)m_report(obj,source_obj,description,count,"all_dropped");all_dropped(obj,source_obj,description, count);// wait for all_dropped cbs to completewait fork;/* NOT NEEDED - Any raise would have killed us!if(!m_total_count.exists(obj))diff_count = -count;elsediff_count = m_total_count[obj] - count;*/// we are ready to delete the 0-count entries for the current// object before propagating up the hierarchy.if (m_source_count.exists(obj) && m_source_count[obj] == 0)m_source_count.delete(obj);if (m_total_count.exists(obj) && m_total_count[obj] == 0)m_total_count.delete(obj);if (!m_prop_mode && obj != m_top)m_drop(m_top,source_obj,description, count, 1);else if (obj != m_top)m_propagate(obj, source_obj, description, count, 0, 1);endtask// m_init_objections// -----------------// Forks off the single background processstatic function void m_init_objections();forkuvm_objection::m_execute_scheduled_forks();join_noneendfunction// Function: set_drain_time//// Sets the drain time on the given ~object~ to ~drain~.//// The drain time is the amount of time to wait once all objections have// been dropped before calling the all_dropped callback and propagating// the objection to the parent.//// If a new objection for this ~object~ or any of its descendants is raised// during the drain time or during execution of the all_dropped callbacks,// the drain_time/all_dropped execution is terminated.// AE: set_drain_time(drain,obj=null)?function void set_drain_time (uvm_object obj=null, time drain);if (obj==null)obj = m_top;m_drain_time[obj] = drain;endfunction//----------------------// Group: Callback Hooks//----------------------// Function: raised//// Objection callback that is called when a <raise_objection> has reached ~obj~.// The default implementation calls <uvm_component::raised>.virtual function void raised (uvm_object obj,uvm_object source_obj,string description,int count);uvm_component comp;if ($cast(comp,obj))comp.raised(this, source_obj, description, count);`uvm_do_callbacks(uvm_objection,uvm_objection_callback,raised(this,obj,source_obj,description,count))if (m_events.exists(obj))->m_events[obj].raised;endfunction// Function: dropped//// Objection callback that is called when a <drop_objection> has reached ~obj~.// The default implementation calls <uvm_component::dropped>.virtual function void dropped (uvm_object obj,uvm_object source_obj,string description,int count);uvm_component comp;if($cast(comp,obj))comp.dropped(this, source_obj, description, count);`uvm_do_callbacks(uvm_objection,uvm_objection_callback,dropped(this,obj,source_obj,description,count))if (m_events.exists(obj))->m_events[obj].dropped;endfunction// Function: all_dropped//// Objection callback that is called when a <drop_objection> has reached ~obj~,// and the total count for ~obj~ goes to zero. This callback is executed// after the drain time associated with ~obj~. The default implementation// calls <uvm_component::all_dropped>.virtual task all_dropped (uvm_object obj,uvm_object source_obj,string description,int count);uvm_component comp;if($cast(comp,obj))comp.all_dropped(this, source_obj, description, count);`uvm_do_callbacks(uvm_objection,uvm_objection_callback,all_dropped(this,obj,source_obj,description,count))if (m_events.exists(obj))->m_events[obj].all_dropped;if (obj == m_top)m_top_all_dropped = 1;endtask//------------------------// Group: Objection Status//------------------------// Function: get_objectors//// Returns the current list of objecting objects (objects that// raised an objection but have not dropped it).function void get_objectors(ref uvm_object list[$]);list.delete();foreach (m_source_count[obj]) list.push_back(obj);endfunction// Task: wait_for//// Waits for the raised, dropped, or all_dropped ~event~ to occur in// the given ~obj~. The task returns after all corresponding callbacks// for that event have been executed.//task wait_for(uvm_objection_event objt_event, uvm_object obj=null);if (obj==null)obj = m_top;if (!m_events.exists(obj)) beginm_events[obj] = new;endm_events[obj].waiters++;case (objt_event)UVM_RAISED: @(m_events[obj].raised);UVM_DROPPED: @(m_events[obj].dropped);UVM_ALL_DROPPED: @(m_events[obj].all_dropped);endcasem_events[obj].waiters--;if (m_events[obj].waiters == 0)m_events.delete(obj);endtasktask wait_for_total_count(uvm_object obj=null, int count=0);if (obj==null)obj = m_top;if(!m_total_count.exists(obj) && count == 0)return;if (count == 0)wait (!m_total_count.exists(obj) && count == 0);elsewait (m_total_count.exists(obj) && m_total_count[obj] == count);endtask// Function: get_objection_count//// Returns the current number of objections raised by the given ~object~.function int get_objection_count (uvm_object obj=null);if (obj==null)obj = m_top;if (!m_source_count.exists(obj))return 0;return m_source_count[obj];endfunction// Function: get_objection_total//// Returns the current number of objections raised by the given ~object~// and all descendants.function int get_objection_total (uvm_object obj=null);if (obj==null)obj = m_top;if (!m_total_count.exists(obj))return 0;elsereturn m_total_count[obj];endfunction// Function: get_drain_time//// Returns the current drain time set for the given ~object~ (default: 0 ns).function time get_drain_time (uvm_object obj=null);if (obj==null)obj = m_top;if (!m_drain_time.exists(obj))return 0;return m_drain_time[obj];endfunction// m_display_objectionsprotected function string m_display_objections(uvm_object obj=null, bit show_header=1);static string blank=" ";string s;int total;uvm_object list[string];uvm_object curr_obj;int depth;string name;string this_obj_name;string curr_obj_name;foreach (m_total_count[o]) beginuvm_object theobj = o;if ( m_total_count[o] > 0)list[theobj.get_full_name()] = theobj;endif (obj==null)obj = m_top;total = get_objection_total(obj);s = $sformatf("The total objection count is %0d\n",total);if (total == 0)return s;s = {s,"---------------------------------------------------------\n"};s = {s,"Source Total \n"};s = {s,"Count Count Object\n"};s = {s,"---------------------------------------------------------\n"};this_obj_name = obj.get_full_name();curr_obj_name = this_obj_name;do begincurr_obj = list[curr_obj_name];// determine depthdepth=0;foreach (curr_obj_name[i])if (curr_obj_name[i] == ".")depth++;// determine leaf namename = curr_obj_name;for (int i=curr_obj_name.len()-1;i >= 0; i--)if (curr_obj_name[i] == ".") beginname = curr_obj_name.substr(i+1,curr_obj_name.len()-1);break;endif (curr_obj_name == "")name = "uvm_top";elsedepth++;// print its = {s, $sformatf("%-6d %-6d %s%s\n",m_source_count.exists(curr_obj) ? m_source_count[curr_obj] : 0,m_total_count.exists(curr_obj) ? m_total_count[curr_obj] : 0,blank.substr(0,2*depth), name)};end while (list.next(curr_obj_name) &&curr_obj_name.substr(0,this_obj_name.len()-1) == this_obj_name);s = {s,"---------------------------------------------------------\n"};return s;endfunctionfunction string convert2string();return m_display_objections(m_top,1);endfunction// Function: display_objections//// Displays objection information about the given ~object~. If ~object~ is// not specified or ~null~, the implicit top-level component, <uvm_root>, is// chosen. The ~show_header~ argument allows control of whether a header is// output.function void display_objections(uvm_object obj=null, bit show_header=1);string m = m_display_objections(obj,show_header);`uvm_info("UVM/OBJ/DISPLAY",m,UVM_NONE)endfunction// Below is all of the basic data stuff that is needed for a uvm_object// for factory registration, printing, comparing, etc.typedef uvm_object_registry#(uvm_objection,"uvm_objection") type_id;static function type_id get_type();return type_id::get();endfunctionfunction uvm_object create (string name="");uvm_objection tmp = new(name);return tmp;endfunctionvirtual function string get_type_name ();return "uvm_objection";endfunctionfunction void do_copy (uvm_object rhs);uvm_objection _rhs;$cast(_rhs, rhs);m_source_count = _rhs.m_source_count;m_total_count = _rhs.m_total_count;m_drain_time = _rhs.m_drain_time;m_prop_mode = _rhs.m_prop_mode;endfunctionendclass// TODO: change to plusarg//`define UVM_DEFAULT_TIMEOUT 9200stypedef class uvm_cmdline_processor;//------------------------------------------------------------------------------//// Class- uvm_test_done_objection DEPRECATED//// Provides built-in end-of-test coordination//------------------------------------------------------------------------------class uvm_test_done_objection extends uvm_objection;protected static uvm_test_done_objection m_inst;protected bit m_forced;// For communicating all objections dropped and end of phasinglocal bit m_executing_stop_processes;local int m_n_stop_threads;// Function- new DEPRECATED//// Creates the singleton test_done objection. Users must not call// this method directly.function new(string name="uvm_test_done");super.new(name);endfunction// Function- qualify DEPRECATED//// Checks that the given ~object~ is derived from either <uvm_component> or// <uvm_sequence_base>.virtual function void qualify(uvm_object obj=null,bit is_raise,string description);uvm_component c;uvm_sequence_base s;string nm = is_raise ? "raise_objection" : "drop_objection";string desc = description == "" ? "" : {" (\"", description, "\")"};if(! ($cast(c,obj) || $cast(s,obj))) beginuvm_report_error("TEST_DONE_NOHIER", {"A non-hierarchical object, '",obj.get_full_name(), "' (", obj.get_type_name(),") was used in a call ","to uvm_test_done.", nm,"(). For this objection, a sequence ","or component is required.", desc });endendfunction`ifndef UVM_NO_DEPRECATED// m_do_stop_all// -------------task m_do_stop_all(uvm_component comp);string name;// we use an external traversal to ensure all forks are// made from a single threaad.if (comp.get_first_child(name))do beginm_do_stop_all(comp.get_child(name));endwhile (comp.get_next_child(name));if (comp.enable_stop_interrupt) beginm_n_stop_threads++;fork begincomp.stop_phase(run_ph);m_n_stop_threads--;endjoin_noneendendtask// Function- stop_request DEPRECATED//// Calling this function triggers the process of shutting down the currently// running task-based phase. This process involves calling all components'// stop tasks for those components whose enable_stop_interrupt bit is set.// Once all stop tasks return, or once the optional global_stop_timeout// expires, all components' kill method is called, effectively ending the// current phase. The uvm_top will then begin execution of the next phase,// if any.function void stop_request();`uvm_info_context("STOP_REQ","Stop-request called. Waiting for all-dropped on uvm_test_done",UVM_FULL,m_top);forkm_stop_request();join_noneendfunctiontask m_stop_request();raise_objection(m_top,"stop_request called; raising test_done objection");uvm_wait_for_nba_region();drop_objection(m_top,"stop_request called; dropping test_done objection");endtask// Variable- stop_timeout DEPRECATED//// These set watchdog timers for task-based phases and stop tasks. You cannot// disable the timeouts. When set to 0, a timeout of the maximum time possible// is applied. A timeout at this value usually indicates a problem with your// testbench. You should lower the timeout to prevent "never-ending"// simulations.time stop_timeout = 0;// Task- all_dropped DEPRECATED//// This callback is called when the given ~object's~ objection count reaches// zero; if the ~object~ is the implicit top-level, <uvm_root> then it means// there are no more objections raised for the ~uvm_test_done~ objection.// Thus, after calling <uvm_objection::all_dropped>, this method will call// <global_stop_request> to stop the current task-based phase (e.g. run).virtual task all_dropped (uvm_object obj,uvm_object source_obj,string description,int count);if (obj != m_top) beginsuper.all_dropped(obj,source_obj,description,count);return;endm_top.all_dropped(this, source_obj, description, count);// All stop tasks are forked from a single thread within a 'guard' process// so 'disable fork' can be used.if(m_cleared == 0) begin`uvm_info_context("TEST_DONE","All end-of-test objections have been dropped. Calling stop tasks",UVM_FULL,m_top);fork begin // guardforkbeginm_executing_stop_processes = 1;m_do_stop_all(m_top);wait (m_n_stop_threads == 0);m_executing_stop_processes = 0;endbeginif (stop_timeout == 0)wait(stop_timeout != 0);`uvm_delay(stop_timeout)`uvm_error("STOP_TIMEOUT",{$sformatf("Stop-task timeout of %0t expired. ", stop_timeout),"'run' phase ready to proceed to extract phase"})endjoin_anydisable fork;endjoin // guard`uvm_info_context("TEST_DONE", {"'run' phase is ready ","to proceed to the 'extract' phase"}, UVM_LOW,m_top)endif (m_events.exists(obj))->m_events[obj].all_dropped;m_top_all_dropped = 1;endtask// Function- raise_objection DEPRECATED//// Calls <uvm_objection::raise_objection> after calling <qualify>.// If the ~object~ is not provided or is ~null~, then the implicit top-level// component, ~uvm_top~, is chosen.virtual function void raise_objection (uvm_object obj=null,string description="",int count=1);if(obj==null)obj=m_top;elsequalify(obj, 1, description);if (m_executing_stop_processes) beginstring desc = description == "" ? "" : {"(\"", description, "\") "};`uvm_warning("ILLRAISE", {"The uvm_test_done objection was ","raised ", desc, "during processing of a stop_request, i.e. stop ","task execution. The objection is ignored by the stop process"})return;endsuper.raise_objection(obj,description,count);endfunction// Function- drop_objection DEPRECATED//// Calls <uvm_objection::drop_objection> after calling <qualify>.// If the ~object~ is not provided or is ~null~, then the implicit top-level// component, ~uvm_top~, is chosen.virtual function void drop_objection (uvm_object obj=null,string description="",int count=1);if(obj==null)obj=m_top;elsequalify(obj, 0, description);super.drop_objection(obj,description,count);endfunction// Task- force_stop DEPRECATED//// Forces the propagation of the all_dropped() callback, even if there are still// outstanding objections. The net effect of this action is to forcibly end// the current phase.virtual task force_stop(uvm_object obj=null);uvm_report_warning("FORCE_STOP",{"Object '",(obj!=null?obj.get_name():"<unknown>"),"' called force_stop"});m_cleared = 1;all_dropped(m_top,obj,"force_stop() called",1);clear(obj);endtask`endif// Below are basic data operations needed for all uvm_objects// for factory registration, printing, comparing, etc.typedef uvm_object_registry#(uvm_test_done_objection,"uvm_test_done") type_id;static function type_id get_type();return type_id::get();endfunctionfunction uvm_object create (string name="");uvm_test_done_objection tmp = new(name);return tmp;endfunctionvirtual function string get_type_name ();return "uvm_test_done";endfunctionstatic function uvm_test_done_objection get();if(m_inst == null)m_inst = uvm_test_done_objection::type_id::create("run");return m_inst;endfunctionendclass// Have a pool of context objects to useclass uvm_objection_context_object;uvm_object obj;uvm_object source_obj;string description;int count;uvm_objection objection;// Clears the values stored within the object,// preventing memory leaks from reused objectsfunction void clear();obj = null;source_obj = null;description = "";count = 0;objection = null;endfunction : clearendclass// Typedef - Exists for backwards compattypedef uvm_objection uvm_callbacks_objection;//------------------------------------------------------------------------------//// Class: uvm_objection_callback////------------------------------------------------------------------------------// The uvm_objection is the callback type that defines the callback// implementations for an objection callback. A user uses the callback// type uvm_objection_cbs_t to add callbacks to specific objections.//// For example:////| class my_objection_cb extends uvm_objection_callback;//| function new(string name);//| super.new(name);//| endfunction//|//| virtual function void raised (uvm_objection objection, uvm_object obj,//| uvm_object source_obj, string description, int count);//| `uvm_info("RAISED","%0t: Objection %s: Raised for %s", $time, objection.get_name(),//| obj.get_full_name());//| endfunction//| endclass//| ...//| initial begin//| my_objection_cb cb = new("cb");//| uvm_objection_cbs_t::add(null, cb); //typewide callback//| endclass uvm_objection_callback extends uvm_callback;function new(string name);super.new(name);endfunction// Function: raised//// Objection raised callback function. Called by <uvm_objection::raised>.virtual function void raised (uvm_objection objection, uvm_object obj,uvm_object source_obj, string description, int count);endfunction// Function: dropped//// Objection dropped callback function. Called by <uvm_objection::dropped>.virtual function void dropped (uvm_objection objection, uvm_object obj,uvm_object source_obj, string description, int count);endfunction// Function: all_dropped//// Objection all_dropped callback function. Called by <uvm_objection::all_dropped>.virtual task all_dropped (uvm_objection objection, uvm_object obj,uvm_object source_obj, string description, int count);endtaskendclass`endif
