//
//------------------------------------------------------------------------------
// Copyright 2007-2010 Mentor Graphics Corporation
// Copyright 2007-2011 Cadence Design Systems, Inc.
// Copyright 2010 Synopsys, Inc.
// Copyright 2014 NVIDIA Corportation
// 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.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//
// CLASS: uvm_event_base
//
// The uvm_event_base class is an abstract wrapper class around the SystemVerilog event
// construct. It provides some additional services such as setting callbacks
// and maintaining the number of waiters.
//
//------------------------------------------------------------------------------
virtual class [docs]uvm_event_base extends uvm_object;
const static string type_name = "uvm_event_base";
protected event m_event;
protected int num_waiters;
protected bit on;
protected time trigger_time=0;
protected uvm_event_callback callbacks[$];
// Function: new
//
// Creates a new event object.
function [docs]new (string name="");
super.new(name);
endfunction
//---------//
// waiting //
//---------//
// Task: wait_on
//
// Waits for the event to be activated for the first time.
//
// If the event has already been triggered, this task returns immediately.
// If ~delta~ is set, the caller will be forced to wait a single delta #0
// before returning. This prevents the caller from returning before
// previously waiting processes have had a chance to resume.
//
// Once an event has been triggered, it will be remain "on" until the event
// is <reset>.
virtual task [docs]wait_on (bit delta = 0);
if (on) begin
if (delta)
#0;
return;
end
num_waiters++;
@on;
endtask
// Task: wait_off
//
// If the event has already triggered and is "on", this task waits for the
// event to be turned "off" via a call to <reset>.
//
// If the event has not already been triggered, this task returns immediately.
// If ~delta~ is set, the caller will be forced to wait a single delta #0
// before returning. This prevents the caller from returning before
// previously waiting processes have had a chance to resume.
virtual task [docs]wait_off (bit delta = 0);
if (!on) begin
if (delta)
#0;
return;
end
num_waiters++;
@on;
endtask
// Task: wait_trigger
//
// Waits for the event to be triggered.
//
// If one process calls wait_trigger in the same delta as another process
// calls <uvm_event#(T)::trigger>, a race condition occurs. If the call to wait occurs
// before the trigger, this method will return in this delta. If the wait
// occurs after the trigger, this method will not return until the next
// trigger, which may never occur and thus cause deadlock.
virtual task [docs]wait_trigger ();
num_waiters++;
@m_event;
endtask
// Task: wait_ptrigger
//
// Waits for a persistent trigger of the event. Unlike <wait_trigger>, this
// views the trigger as persistent within a given time-slice and thus avoids
// certain race conditions. If this method is called after the trigger but
// within the same time-slice, the caller returns immediately.
virtual task [docs]wait_ptrigger ();
if (m_event.triggered)
return;
num_waiters++;
@m_event;
endtask
// Function: get_trigger_time
//
// Gets the time that this event was last triggered. If the event has not been
// triggered, or the event has been reset, then the trigger time will be 0.
virtual function time [docs]get_trigger_time ();
return trigger_time;
endfunction
//-------//
// state //
//-------//
// Function: is_on
//
// Indicates whether the event has been triggered since it was last reset.
//
// A return of 1 indicates that the event has triggered.
virtual function bit [docs]is_on ();
return (on == 1);
endfunction
// Function: is_off
//
// Indicates whether the event has been triggered or been reset.
//
// A return of 1 indicates that the event has not been triggered.
virtual function bit [docs]is_off ();
return (on == 0);
endfunction
// Function: reset
//
// Resets the event to its off state. If ~wakeup~ is set, then all processes
// currently waiting for the event are activated before the reset.
//
// No callbacks are called during a reset.
virtual function void [docs]reset (bit wakeup = 0);
event e;
if (wakeup)
->m_event;
m_event = e;
num_waiters = 0;
on = 0;
trigger_time = 0;
endfunction
//--------------//
// waiters list //
//--------------//
// Function: cancel
//
// Decrements the number of waiters on the event.
//
// This is used if a process that is waiting on an event is disabled or
// activated by some other means.
virtual function void [docs]cancel ();
if (num_waiters > 0)
num_waiters--;
endfunction
// Function: get_num_waiters
//
// Returns the number of processes waiting on the event.
virtual function int [docs]get_num_waiters ();
return num_waiters;
endfunction
virtual function string [docs]get_type_name();
return type_name;
endfunction
virtual function void [docs]do_print (uvm_printer printer);
printer.print_field_int("num_waiters", num_waiters, $bits(num_waiters), UVM_DEC, ".", "int");
printer.print_field_int("on", on, $bits(on), UVM_BIN, ".", "bit");
printer.print_time("trigger_time", trigger_time);
printer.m_scope.down("callbacks");
foreach(callbacks[e]) begin
printer.print_object($sformatf("[%0d]",e), callbacks[e], "[");
end
printer.m_scope.up();
endfunction
virtual function void [docs]do_copy (uvm_object rhs);
uvm_event_base e;
super.do_copy(rhs);
if(!$cast(e, rhs) || (e==null)) return;
m_event = e.m_event;
num_waiters = e.num_waiters;
on = e.on;
trigger_time = e.trigger_time;
callbacks.delete();
callbacks = e.callbacks;
endfunction
endclass
//------------------------------------------------------------------------------
//
// CLASS: uvm_event#(T)
//
// The uvm_event class is an extension of the abstract uvm_event_base class.
//
// The optional parameter ~T~ allows the user to define a data type which
// can be passed during an event trigger.
//------------------------------------------------------------------------------
class [docs]uvm_event#(type T=uvm_object) extends uvm_event_base;
const static string type_name = "uvm_event";
local T trigger_data;
// Function: new
//
// Creates a new event object.
function [docs]new (string name="");
super.new(name);
endfunction
// Task: wait_trigger_data
//
// This method calls <uvm_event_base::wait_trigger> followed by <get_trigger_data>.
virtual task [docs]wait_trigger_data (output T data);
wait_trigger();
data = get_trigger_data();
endtask
// Task: wait_ptrigger_data
//
// This method calls <uvm_event_base::wait_ptrigger> followed by <get_trigger_data>.
virtual task [docs]wait_ptrigger_data (output T data);
wait_ptrigger();
data = get_trigger_data();
endtask
//------------//
// triggering //
//------------//
// Function: trigger
//
// Triggers the event, resuming all waiting processes.
//
// An optional ~data~ argument can be supplied with the enable to provide
// trigger-specific information.
virtual function void [docs]trigger (T data=null);
int skip;
skip=0;
if (callbacks.size()) begin
for (int i=0;i<callbacks.size();i++) begin
uvm_event_callback#(T) tmp=callbacks[i];
skip = skip + tmp.pre_trigger(this,data);
end
end
if (skip==0) begin
->m_event;
if (callbacks.size()) begin
for (int i=0;i<callbacks.size();i++) begin
uvm_event_callback#(T) tmp=callbacks[i];
tmp.post_trigger(this,data);
end
end
num_waiters = 0;
on = 1;
trigger_time = $realtime;
trigger_data = data;
end
endfunction
// Function: get_trigger_data
//
// Gets the data, if any, provided by the last call to <trigger>.
virtual function T [docs]get_trigger_data ();
return trigger_data;
endfunction
virtual function string [docs]get_type_name();
return type_name;
endfunction
//-----------//
// callbacks //
//-----------//
// Function: add_callback
//
// Registers a callback object, ~cb~, with this event. The callback object
// may include pre_trigger and post_trigger functionality. If ~append~ is set
// to 1, the default, ~cb~ is added to the back of the callback list. Otherwise,
// ~cb~ is placed at the front of the callback list.
virtual function void [docs]add_callback (uvm_event_callback#(T) cb, bit append=1);
for (int i=0;i<callbacks.size();i++) begin
if (cb == callbacks[i]) begin
uvm_report_warning("CBRGED","add_callback: Callback already registered. Ignoring.", UVM_NONE);
return;
end
end
if (append)
callbacks.push_back(cb);
else
callbacks.push_front(cb);
endfunction
// Function: delete_callback
//
// Unregisters the given callback, ~cb~, from this event.
virtual function void [docs]delete_callback (uvm_event_callback#(T) cb);
for (int i=0;i<callbacks.size();i++) begin
if (cb == callbacks[i]) begin
callbacks.delete(i);
return;
end
end
uvm_report_warning("CBNTFD", "delete_callback: Callback not found. Ignoring delete request.", UVM_NONE);
endfunction
virtual function void [docs]do_print (uvm_printer printer);
super.do_print(printer);
printer.print_object("trigger_data", trigger_data);
endfunction
virtual function void [docs]do_copy (uvm_object rhs);
uvm_event#(T) e;
super.do_copy(rhs);
if(!$cast(e, rhs) || (e==null)) return;
trigger_data = e.trigger_data;
endfunction // do_copy
virtual function uvm_object [docs]create(string name="");
uvm_event#(T) v;
v=new(name);
return v;
endfunction
endclass