// //------------------------------------------------------------------------------ // Copyright 2011 AMD // Copyright 2007-2018 Cadence Design Systems, Inc. // Copyright 2014 Cisco Systems, Inc. // Copyright 2020 Marvell International Ltd. // Copyright 2007-2011 Mentor Graphics Corporation // Copyright 2013-2020 NVIDIA Corporation // Copyright 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. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // // CLASS -- NODOCS -- 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. // //------------------------------------------------------------------------------ // @uvm-ieee 1800.2-2020 auto 10.1.1.1 virtual class uvm_event_base extends uvm_object; `uvm_object_abstract_utils(uvm_event_base) protected event m_event; protected int num_waiters; protected bit on; protected time trigger_time=0; // Function -- NODOCS -- new // // Creates a new event object. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.1 function new (string name=""); super.new(name); endfunction //---------// // waiting // //---------// // Task -- NODOCS -- 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 . // @uvm-ieee 1800.2-2020 auto 10.1.1.2.2 virtual task wait_on (bit delta = 0); if (on) begin if (delta) #0; return; end num_waiters++; @on; endtask // Task -- NODOCS -- 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 . // // 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. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.3 virtual task wait_off (bit delta = 0); if (!on) begin if (delta) #0; return; end num_waiters++; @on; endtask // Task -- NODOCS -- wait_trigger // // Waits for the event to be triggered. // // If one process calls wait_trigger in the same delta as another process // calls , 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. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.4 virtual task wait_trigger (); num_waiters++; @m_event; endtask // Task -- NODOCS -- wait_ptrigger // // Waits for a persistent trigger of the event. Unlike , 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. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.5 virtual task wait_ptrigger (); if (m_event.triggered) return; num_waiters++; @m_event; endtask // Function -- NODOCS -- 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. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.6 virtual function time get_trigger_time (); return trigger_time; endfunction //-------// // state // //-------// // Function -- NODOCS -- is_on // // Indicates whether the event has been triggered since it was last reset. // // A return of 1 indicates that the event has triggered. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.7 virtual function bit is_on (); return (on == 1); endfunction // Function -- NODOCS -- 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 is_off (); return (on == 0); endfunction // Function -- NODOCS -- 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. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.8 virtual function void 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 -- NODOCS -- 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. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.9 virtual function void cancel (); if (num_waiters > 0) num_waiters--; endfunction // Function -- NODOCS -- get_num_waiters // // Returns the number of processes waiting on the event. // @uvm-ieee 1800.2-2020 auto 10.1.1.2.10 virtual function int get_num_waiters (); return num_waiters; endfunction virtual function void 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); endfunction virtual function void 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; endfunction endclass // Class: uvm_event#(T) // This is an implementation of uvm_event#(T) as described in 1800.2 with // the addition of API described below. // @uvm-ieee 1800.2-2020 auto 10.1.2.1 class uvm_event#(type T=uvm_object) extends uvm_event_base; typedef uvm_event#(T) this_type; typedef uvm_event_callback#(T) cb_type; // Type: cbs_type // Callback typedef for this event type. // // @uvm-contrib Potential Contribution to 1800.2 typedef uvm_callbacks#(this_type, cb_type) cbs_type; // Not using `uvm_register_cb(this_type, cb_type) // so as to try and get ~slightly~ better debug // output for names. static local function bit m_register_cb(); return uvm_callbacks#(this_type,cb_type)::m_register_pair( "uvm_pkg::uvm_event#(T)", "uvm_pkg::uvm_event_callback#(T)" ); endfunction : m_register_cb static local bit m_cb_registered = m_register_cb(); `uvm_object_param_utils(this_type) // Better type name for debug virtual function string get_type_name(); return "uvm_pkg::uvm_event#(T)"; endfunction : get_type_name local T trigger_data; local T default_data; // Function -- NODOCS -- new // // Creates a new event object. // @uvm-ieee 1800.2-2020 auto 10.1.2.2.1 function new (string name=""); super.new(name); endfunction // Function -- NODOCS -- reset // // Resets the event to its off state and clears trigger data to its default state. virtual function void reset (bit wakeup = 0); trigger_data = get_default_data(); super.reset(wakeup); endfunction : reset // Task -- NODOCS -- wait_trigger_data // // This method calls followed by . // @uvm-ieee 1800.2-2020 auto 10.1.2.2.2 virtual task wait_trigger_data (output T data); wait_trigger(); data = get_trigger_data(); endtask // Task -- NODOCS -- wait_ptrigger_data // // This method calls followed by . // @uvm-ieee 1800.2-2020 auto 10.1.2.2.3 virtual task wait_ptrigger_data (output T data); wait_ptrigger(); data = get_trigger_data(); endtask //------------// // triggering // //------------// // Function -- NODOCS -- trigger // // Triggers the event, resuming all waiting processes. // // An optional ~data~ argument can be supplied with the enable to provide // trigger-specific information. // @uvm-ieee 1800.2-2020 auto 10.1.2.2.4 virtual function void trigger (T data=get_default_data()); int skip; cb_type cb_q[$]; skip=0; cbs_type::get_all(cb_q, this); // Call all pre_trigger, bail out after // if any return !0 foreach (cb_q[i]) skip += cb_q[i].pre_trigger(this, data); if (skip==0) begin on = 1; trigger_time = $realtime; trigger_data = data; ->m_event; foreach (cb_q[i]) cb_q[i].post_trigger(this, data); num_waiters = 0; end endfunction // Function -- NODOCS -- get_trigger_data // // Gets the data, if any, provided by the last call to . // @uvm-ieee 1800.2-2020 auto 10.1.2.2.5 virtual function T get_trigger_data (); return trigger_data; endfunction // Function -- NODOCS -- default data // @uvm-ieee 1800.2-2020 auto 10.1.2.2.6 virtual function T get_default_data(); return default_data; endfunction : get_default_data // @uvm-ieee 1800.2-2020 auto 10.1.2.2.6 virtual function void set_default_data(T data); default_data = data; endfunction : set_default_data virtual function void do_print (uvm_printer printer); uvm_event#(uvm_object) oe; cb_type cb_q[$]; super.do_print(printer); // Printing the callbacks cbs_type::get_all(cb_q, this); printer.print_array_header("callbacks", cb_q.size(), "queue"); foreach(cb_q[e]) printer.print_object($sformatf("[%0d]", e), cb_q[e], "["); printer.print_array_footer(cb_q.size()); if ($cast(oe, this)) begin printer.print_object("trigger_data", oe.get_trigger_data()); end else begin uvm_event#(string) se; if ($cast(se, this)) printer.print_string("trigger_data", se.get_trigger_data()); end endfunction virtual function void do_copy (uvm_object rhs); this_type e; cb_type cb_q[$]; super.do_copy(rhs); if(!$cast(e, rhs) || (e==null)) return; trigger_data = e.trigger_data; begin // Copying the callbacks is VERY ugly // // First we retrieve any existing callbacks for this // instance, and delete them. Note that this can // bump into Mantis 6450, which would result in // incorrect behavior until that mantis is fixed. // \todo Remove this note when 6450 is resolved. cbs_type::get_all(cb_q, this); foreach(cb_q[i]) cbs_type::delete(this, cb_q[i]); // We now have an empty instance queue, which we'll fill // using the rhs. cb_q.delete(); cbs_type::get_all(cb_q, e); foreach(cb_q[i]) cbs_type::add(this, cb_q[i]); end endfunction endclass