URL
https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk
Subversion Repositories uart2bus_testbench
[/] [uart2bus_testbench/] [trunk/] [tb/] [uvm_src/] [base/] [uvm_heartbeat.svh] - Rev 16
Compare with Previous | Blame | View Log
//----------------------------------------------------------------------// Copyright 2007-2011 Mentor Graphics Corporation// Copyright 2007-2009 Cadence Design Systems, Inc.// Copyright 2010 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_HEARTBEAT_SVH`define UVM_HEARTBEAT_SVHtypedef enum {UVM_ALL_ACTIVE,UVM_ONE_ACTIVE,UVM_ANY_ACTIVE,UVM_NO_HB_MODE} uvm_heartbeat_modes;typedef class uvm_heartbeat_callback;typedef uvm_callbacks #(uvm_objection,uvm_heartbeat_callback) uvm_heartbeat_cbs_t;//------------------------------------------------------------------------------//// Class: uvm_heartbeat////------------------------------------------------------------------------------// Heartbeats provide a way for environments to easily ensure that their// descendants are alive. A uvm_heartbeat is associated with a specific// objection object. A component that is being tracked by the heartbeat// object must raise (or drop) the synchronizing objection during// the heartbeat window.//// The uvm_heartbeat object has a list of participating objects. The heartbeat// can be configured so that all components (UVM_ALL_ACTIVE), exactly one// (UVM_ONE_ACTIVE), or any component (UVM_ANY_ACTIVE) must trigger the// objection in order to satisfy the heartbeat condition.//------------------------------------------------------------------------------typedef class uvm_objection_callback;class uvm_heartbeat extends uvm_object;protected uvm_objection m_objection;protected uvm_heartbeat_callback m_cb;protected uvm_component m_cntxt;protected uvm_heartbeat_modes m_mode;protected uvm_component m_hblist[$];protected uvm_event#(uvm_object) m_event;protected bit m_started;protected event m_stop_event;// Function: new//// Creates a new heartbeat instance associated with ~cntxt~. The context// is the hierarchical location that the heartbeat objections will flow// through and be monitored at. The ~objection~ associated with the heartbeat// is optional, if it is left ~null~ but it must be set before the heartbeat// monitor will activate.////| uvm_objection myobjection = new("myobjection"); //some shared objection//| class myenv extends uvm_env;//| uvm_heartbeat hb = new("hb", this, myobjection);//| ...//| endclassfunction new(string name, uvm_component cntxt, uvm_objection objection=null);uvm_coreservice_t cs;super.new(name);m_objection = objection;cs = uvm_coreservice_t::get();//if a cntxt is given it will be used for reporting.if(cntxt != null) m_cntxt = cntxt;else m_cntxt = cs.get_root();m_cb = new({name,"_cb"},m_cntxt);endfunction// Function: set_mode//// Sets or retrieves the heartbeat mode. The current value for the heartbeat// mode is returned. If an argument is specified to change the mode then the// mode is changed to the new value.function uvm_heartbeat_modes set_mode (uvm_heartbeat_modes mode = UVM_NO_HB_MODE);set_mode = m_mode;if(mode == UVM_ANY_ACTIVE || mode == UVM_ONE_ACTIVE || mode == UVM_ALL_ACTIVE)m_mode = mode;endfunction// Function: set_heartbeat//// Sets up the heartbeat event and assigns a list of objects to watch. The// monitoring is started as soon as this method is called. Once the// monitoring has been started with a specific event, providing a new// monitor event results in an error. To change trigger events, you// must first <stop> the monitor and then <start> with a new event trigger.//// If the trigger event ~e~ is ~null~ and there was no previously set// trigger event, then the monitoring is not started. Monitoring can be// started by explicitly calling <start>.function void set_heartbeat (uvm_event#(uvm_object) e, ref uvm_component comps[$]);uvm_object c;foreach(comps[i]) beginc = comps[i];if(!m_cb.cnt.exists(c))m_cb.cnt[c]=0;if(!m_cb.last_trigger.exists(c))m_cb.last_trigger[c]=0;endif(e==null && m_event==null) return;start(e);endfunction// Function: add//// Add a single component to the set of components to be monitored.// This does not cause monitoring to be started. If monitoring is// currently active then this component will be immediately added// to the list of components and will be expected to participate// in the currently active event window.function void add (uvm_component comp);uvm_object c = comp;if(m_cb.cnt.exists(c)) return;m_cb.cnt[c]=0;m_cb.last_trigger[c]=0;endfunction// Function: remove//// Remove a single component to the set of components being monitored.// Monitoring is not stopped, even if the last component has been// removed (an explicit stop is required).function void remove (uvm_component comp);uvm_object c = comp;if(m_cb.cnt.exists(c)) m_cb.cnt.delete(c);if(m_cb.last_trigger.exists(c)) m_cb.last_trigger.delete(c);endfunction// Function: start//// Starts the heartbeat monitor. If ~e~ is ~null~ then whatever event// was previously set is used. If no event was previously set then// a warning is issued. It is an error if the monitor is currently// running and ~e~ is specifying a different trigger event from the// current event.function void start (uvm_event#(uvm_object) e=null);if(m_event == null && e == null) beginm_cntxt.uvm_report_warning("NOEVNT", { "start() was called for: ",get_name(), " with a null trigger and no currently set trigger" },UVM_NONE);return;endif((m_event != null) && (e != m_event) && m_started) beginm_cntxt.uvm_report_error("ILHBVNT", { "start() was called for: ",get_name(), " with trigger ", e.get_name(), " which is different ","from the original trigger ", m_event.get_name() }, UVM_NONE);return;endif(e != null) m_event = e;m_enable_cb();m_start_hb_process();endfunction// Function: stop//// Stops the heartbeat monitor. Current state information is reset so// that if <start> is called again the process will wait for the first// event trigger to start the monitoring.function void stop ();m_started = 0;->m_stop_event;m_disable_cb();endfunctionfunction void m_start_hb_process();if(m_started) return;m_started = 1;forkm_hb_process;join_noneendfunctionprotected bit m_added;function void m_enable_cb;void'(m_cb.callback_mode(1));if(m_objection == null) return;if(!m_added)uvm_heartbeat_cbs_t::add(m_objection, m_cb);m_added = 1;endfunctionfunction void m_disable_cb;void'(m_cb.callback_mode(0));endfunctiontask m_hb_process;uvm_object obj;bit triggered;time last_trigger=0;forkbegin// The process waits for the event trigger. The first trigger is// ignored, but sets the first start window. On susequent triggers// the monitor tests that the mode criteria was full-filled.while(1) beginm_event.wait_trigger();if(triggered) begincase (m_mode)UVM_ALL_ACTIVE:beginforeach(m_cb.cnt[idx]) beginobj = idx;if(!m_cb.cnt[obj]) beginm_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s for component %s since last event trigger at time %0t : last update time was %0t",m_objection.get_name(), obj.get_full_name(),last_trigger, m_cb.last_trigger[obj]), UVM_NONE);endendendUVM_ANY_ACTIVE:beginif(m_cb.cnt.num() && !m_cb.objects_triggered()) beginstring s;foreach(m_cb.cnt[idx]) beginobj = idx;s={s,"\n ",obj.get_full_name()};endm_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s on any component since last event trigger at time %0t. The list of registered components is:%s",m_objection.get_name(), last_trigger, s), UVM_NONE);endendUVM_ONE_ACTIVE:beginif(m_cb.objects_triggered() > 1) beginstring s;foreach(m_cb.cnt[idx]) beginobj = idx;if(m_cb.cnt[obj]) $swrite(s,"%s\n %s (updated: %0t)",s, obj.get_full_name(), m_cb.last_trigger[obj]);endm_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Recieved update of %s from more than one component since last event trigger at time %0t. The list of triggered components is:%s",m_objection.get_name(), last_trigger, s), UVM_NONE);endif(m_cb.cnt.num() && !m_cb.objects_triggered()) beginstring s;foreach(m_cb.cnt[idx]) beginobj = idx;s={s,"\n ",obj.get_full_name()};endm_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s on any component since last event trigger at time %0t. The list of registered components is:%s",m_objection.get_name(), last_trigger, s), UVM_NONE);endendendcaseendm_cb.reset_counts();last_trigger = $realtime;triggered = 1;endend@(m_stop_event);join_anydisable fork;endtaskendclassclass uvm_heartbeat_callback extends uvm_objection_callback;int cnt [uvm_object];time last_trigger [uvm_object];uvm_object target;uvm_coreservice_t cs = uvm_coreservice_t::get();function new(string name, uvm_object target);super.new(name);if (target != null)this.target = target;elsethis.target = cs.get_root();endfunctionvirtual function void raised (uvm_objection objection,uvm_object obj,uvm_object source_obj,string description,int count);if(obj == target) beginif(!cnt.exists(source_obj))cnt[source_obj] = 0;cnt[source_obj] = cnt[source_obj]+1;last_trigger[source_obj] = $realtime;endendfunctionvirtual function void dropped (uvm_objection objection,uvm_object obj,uvm_object source_obj,string description,int count);raised(objection,obj,source_obj,description,count);endfunctionfunction void reset_counts;foreach(cnt[i]) cnt[i] = 0;endfunctionfunction int objects_triggered;objects_triggered = 0;foreach(cnt[i])if (cnt[i] != 0)objects_triggered++;endfunctionendclass`endif
