diff --git a/test_regress/t/t_uvm/base/uvm_barrier.svh b/test_regress/t/t_uvm/base/uvm_barrier.svh new file mode 100644 index 0000000000..11edbdb412 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_barrier.svh @@ -0,0 +1,204 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2013-2018 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. +//------------------------------------------------------------------------------ + + +//----------------------------------------------------------------------------- +// +// CLASS -- NODOCS -- uvm_barrier +// +// The uvm_barrier class provides a multiprocess synchronization mechanism. +// It enables a set of processes to block until the desired number of processes +// get to the synchronization point, at which time all of the processes are +// released. +//----------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 10.3.1 +class uvm_barrier extends uvm_object; + + local int threshold; + local int num_waiters; + local bit at_threshold; + local bit auto_reset; + local uvm_event#(uvm_object) m_event; + + `uvm_object_utils(uvm_barrier) + + // Function -- NODOCS -- new + // + // Creates a new barrier object. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.1 + function new (string name="", int threshold=0); + super.new(name); + m_event = new({"barrier_",name}); + this.threshold = threshold; + num_waiters = 0; + auto_reset = 1; + at_threshold = 0; + endfunction + + + // Task -- NODOCS -- wait_for + // + // Waits for enough processes to reach the barrier before continuing. + // + // The number of processes to wait for is set by the method. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.2 + virtual task wait_for(); + + if (at_threshold) + return; + + num_waiters++; + + if (num_waiters >= threshold) begin + if (!auto_reset) + at_threshold=1; + m_trigger(); + return; + end + + m_event.wait_trigger(); + + endtask + + + // Function -- NODOCS -- reset + // + // Resets the barrier. This sets the waiter count back to zero. + // + // The threshold is unchanged. After reset, the barrier will force processes + // to wait for the threshold again. + // + // If the ~wakeup~ bit is set, any currently waiting processes will + // be activated. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.3 + virtual function void reset (bit wakeup=1); + at_threshold = 0; + if (num_waiters) begin + if (wakeup) + m_event.trigger(); + else + m_event.reset(); + end + num_waiters = 0; + endfunction + + + // Function -- NODOCS -- set_auto_reset + // + // Determines if the barrier should reset itself after the threshold is + // reached. + // + // The default is on, so when a barrier hits its threshold it will reset, and + // new processes will block until the threshold is reached again. + // + // If auto reset is off, then once the threshold is achieved, new processes + // pass through without being blocked until the barrier is reset. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.4 + virtual function void set_auto_reset (bit value=1); + at_threshold = 0; + auto_reset = value; + endfunction + + + // Function -- NODOCS -- set_threshold + // + // Sets the process threshold. + // + // This determines how many processes must be waiting on the barrier before + // the processes may proceed. + // + // Once the ~threshold~ is reached, all waiting processes are activated. + // + // If ~threshold~ is set to a value less than the number of currently + // waiting processes, then the barrier is reset and waiting processes are + // activated. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.6 + virtual function void set_threshold (int threshold); + this.threshold = threshold; + if (threshold <= num_waiters) + reset(1); + endfunction + + + // Function -- NODOCS -- get_threshold + // + // Gets the current threshold setting for the barrier. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.5 + virtual function int get_threshold (); + return threshold; + endfunction + + + // Function -- NODOCS -- get_num_waiters + // + // Returns the number of processes currently waiting at the barrier. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.7 + virtual function int get_num_waiters (); + return num_waiters; + endfunction + + + // Function -- NODOCS -- cancel + // + // Decrements the waiter count by one. This is used when a process that is + // waiting on the barrier is killed or activated by some other means. + + // @uvm-ieee 1800.2-2017 auto 10.3.2.8 + virtual function void cancel (); + m_event.cancel(); + num_waiters = m_event.get_num_waiters(); + endfunction + + local task m_trigger(); + m_event.trigger(); + num_waiters=0; + #0; //this process was last to wait; allow other procs to resume first + endtask + + virtual function void do_print (uvm_printer printer); + printer.print_field_int("threshold", threshold, $bits(threshold), UVM_DEC, ".", "int"); + printer.print_field_int("num_waiters", num_waiters, $bits(num_waiters), UVM_DEC, ".", "int"); + printer.print_field_int("at_threshold", at_threshold, $bits(at_threshold), UVM_BIN, ".", "bit"); + printer.print_field_int("auto_reset", auto_reset, $bits(auto_reset), UVM_BIN, ".", "bit"); + endfunction + + virtual function void do_copy (uvm_object rhs); + uvm_barrier b; + super.do_copy(rhs); + if(!$cast(b, rhs) || (b==null)) return; + + threshold = b.threshold; + num_waiters = b.num_waiters; + at_threshold = b.at_threshold; + auto_reset = b.auto_reset; + m_event = b.m_event; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_base.svh b/test_regress/t/t_uvm/base/uvm_base.svh new file mode 100644 index 0000000000..297e27423e --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_base.svh @@ -0,0 +1,121 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, Inc. +// Copyright 2011 Cypress Semiconductor Corp. +// Copyright 2010-2018 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. +//---------------------------------------------------------------------- + +`ifndef UVM_BASE_SVH +`define UVM_BASE_SVH + + typedef class uvm_cmdline_processor; + + + + // Miscellaneous classes and functions. uvm_void is defined in uvm_misc, + // along with some auxillary functions that UVM needs but are not really + // part of UVM. + `include "base/uvm_version.svh" + `include "base/uvm_object_globals.svh" + `include "base/uvm_misc.svh" + + `include "base/uvm_coreservice.svh" + `include "base/uvm_globals.svh" + + + // The base object element. Contains data methods (, etc) and + // factory creation methods (). Also includes control classes. + `include "base/uvm_object.svh" + + `include "base/uvm_factory.svh" + `include "base/uvm_registry.svh" + + `include "base/uvm_pool.svh" + `include "base/uvm_queue.svh" + + + // Resources/configuration facility + `include "base/uvm_spell_chkr.svh" + `include "base/uvm_resource_base.svh" + `include "base/uvm_resource.svh" + `include "base/uvm_resource_specializations.svh" + `include "base/uvm_resource_db.svh" + `include "base/uvm_resource_db_options.svh" + `include "base/uvm_config_db.svh" + + + // Policies + `include "base/uvm_policy.svh" + `include "base/uvm_field_op.svh" + `include "base/uvm_copier.svh" + `include "base/uvm_printer.svh" + `include "base/uvm_comparer.svh" + `include "base/uvm_packer.svh" + `include "base/uvm_links.svh" + `include "base/uvm_tr_database.svh" + `include "base/uvm_text_tr_database.svh" + `include "base/uvm_tr_stream.svh" + `include "base/uvm_text_tr_stream.svh" + `include "base/uvm_recorder.svh" + + // Event interface + `include "base/uvm_event_callback.svh" + `include "base/uvm_event.svh" + `include "base/uvm_barrier.svh" + + // Callback interface + `include "base/uvm_callback.svh" + + // Reporting interface + `include "base/uvm_report_message.svh" + `include "base/uvm_report_catcher.svh" + `include "base/uvm_report_server.svh" + `include "base/uvm_report_handler.svh" + `include "base/uvm_report_object.svh" + + // Base transaction object + `include "base/uvm_transaction.svh" + + // The phase declarations + `include "base/uvm_phase.svh" + `include "base/uvm_domain.svh" + `include "base/uvm_bottomup_phase.svh" + `include "base/uvm_topdown_phase.svh" + `include "base/uvm_task_phase.svh" + `include "base/uvm_common_phases.svh" + `include "base/uvm_runtime_phases.svh" + + `include "base/uvm_run_test_callback.svh" + `include "base/uvm_component.svh" + + // Objection interface + `include "base/uvm_objection.svh" + `include "base/uvm_heartbeat.svh" + + + // Command Line Processor + `include "base/uvm_cmdline_processor.svh" + + // traversal utilities + `include "base/uvm_traversal.svh" + +`endif // UVM_BASE_SVH diff --git a/test_regress/t/t_uvm/base/uvm_bottomup_phase.svh b/test_regress/t/t_uvm/base/uvm_bottomup_phase.svh new file mode 100644 index 0000000000..dfe77bfcce --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_bottomup_phase.svh @@ -0,0 +1,106 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2011 AMD +// Copyright 2015 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_bottomup_phase +// +//------------------------------------------------------------------------------ +// Virtual base class for function phases that operate bottom-up. +// The pure virtual function execute() is called for each component. +// This is the default traversal so is included only for naming. +// +// A bottom-up function phase completes when the method +// has been called and returned on all applicable components +// in the hierarchy. + +// @uvm-ieee 1800.2-2017 auto 9.5.1 +virtual class uvm_bottomup_phase extends uvm_phase; + + + // @uvm-ieee 1800.2-2017 auto 9.5.2.1 + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.5.2.2 + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain =phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + + if (comp.get_first_child(name)) + do + traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + + if (m_phase_trace) + `uvm_info("PH_TRACE",$sformatf("bottomup-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", + phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), + UVM_DEBUG) + + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + end + UVM_PHASE_EXECUTING: begin + uvm_phase ph = this; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + `uvm_fatal("PH_BADEXEC","bottomup phase traverse internal error") + endcase + end + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.5.2.3 + virtual function void execute(uvm_component comp, + uvm_phase phase); + // reseed this process for random stability + process proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + + comp.m_current_phase = phase; + exec_func(comp,phase); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_callback.svh b/test_regress/t/t_uvm/base/uvm_callback.svh index 8b3405b373..5a47d3a3ca 100644 --- a/test_regress/t/t_uvm/base/uvm_callback.svh +++ b/test_regress/t/t_uvm/base/uvm_callback.svh @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 -// //---------------------------------------------------------------------- // Copyright 2007-2018 Cadence Design Systems, Inc. // Copyright 2007-2011 Mentor Graphics Corporation @@ -25,7 +23,7 @@ // permissions and limitations under the License. //---------------------------------------------------------------------- -//UVM `include "uvm_macros.svh" +`include "uvm_macros.svh" //------------------------------------------------------------------------------ // Title: Callbacks Classes @@ -34,18 +32,10 @@ // and user-defined callbacks. //------------------------------------------------------------------------------ -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- - typedef class uvm_root; typedef class uvm_callback; typedef class uvm_callbacks_base; -// UVM ! -typedef enum {UVM_APPEND, UVM_PREPEND} uvm_apprepend; -// UVM //------------------------------------------------------------------------------ // @@ -86,7 +76,7 @@ endclass // // Base class singleton that holds generic queues for all instance // specific objects. This is an internal class. This class contains a -// global pool that has all of the instance specific callback queues in it. +// global pool that has all of the instance specific callback queues in it. // All of the typewide callback queues live in the derivative class // uvm_typed_callbacks#(T). This is not a user visible class. // @@ -117,7 +107,7 @@ class uvm_callbacks_base extends uvm_object; //Type checking interface this_type m_this_type[$]; //one to many T->T/CB - uvm_typeid_base m_super_type; //one to one relation + uvm_typeid_base m_super_type; //one to one relation uvm_typeid_base m_derived_types[$]; //one to many relation virtual function bit m_am_i_a(uvm_object obj); @@ -182,7 +172,7 @@ endclass // callbacks. It also contains some of the public interface methods, // but those methods are accessed via the uvm_callbacks#() class // so they are documented in that class even though the implementation -// is in this class. +// is in this class. // // The , , and methods are implemented in this class. @@ -198,13 +188,6 @@ class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; //just a reference to the object that is generated in the derived class. static this_type m_t_inst; - // UVM ! - static function void uvmt_drop_globals(); - m_tw_cb_q.delete(); - m_t_inst = null; - endfunction - // UVM ! - static function this_type m_initialize(); if(m_t_inst == null) begin void'(super_type::m_initialize()); @@ -385,7 +368,7 @@ class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; while(m_t_inst.m_pool.next(bobj)); end if(me != null || m_t_inst.m_tw_cb_q.size()) begin - qs.push_back($sformatf("Registered callbacks for all instances of %s\n", tname)); + qs.push_back($sformatf("Registered callbacks for all instances of %s\n", tname)); qs.push_back("---------------------------------------------------------------\n"); end if(me != null) begin @@ -402,7 +385,7 @@ class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; inst_q.push_back(bobj.get_full_name()); if(cb.is_enabled()) mode_q.push_back("ON"); else mode_q.push_back("OFF"); - + str = cb.get_name(); max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len(); str = bobj.get_full_name(); @@ -417,7 +400,7 @@ class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; end else begin if(m_t_inst.m_pool.exists(bobj) || m_t_inst.m_tw_cb_q.size()) begin - qs.push_back($sformatf("Registered callbacks for instance %s of %s\n", obj.get_full_name(), tname)); + qs.push_back($sformatf("Registered callbacks for instance %s of %s\n", obj.get_full_name(), tname)); qs.push_back("---------------------------------------------------------------\n"); end if(m_t_inst.m_pool.exists(bobj)) begin @@ -449,7 +432,7 @@ class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; foreach (cbq[i]) begin qs.push_back($sformatf("%s %s %s on %s %s\n", cbq[i], blanks.substr(0,max_cb_name-cbq[i].len()-1), inst_q[i], blanks.substr(0,max_inst_name - inst_q[i].len()-1), mode_q[i])); end -//UVM `uvm_info("UVM/CB/DISPLAY",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE) + `uvm_info("UVM/CB/DISPLAY",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE) m_tracing = 1; //allow tracing to be resumed endfunction @@ -469,7 +452,7 @@ endclass // customize certain behaviors of the component in a manner that is controlled // by the component developer. The integrity of the component's overall behavior // is intact, while still allowing certain customizable actions by the user. -// +// // To enable compile-time type-safety, the class is parameterized on both the // user-defined callback interface implementation as well as the object type // associated with the callback. The object type-callback type pair are @@ -496,7 +479,7 @@ endclass // // | class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) // - + // @uvm-ieee 1800.2-2017 auto 10.7.2.1 class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) extends uvm_typed_callbacks#(T); @@ -511,10 +494,10 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) // // This type parameter specifies the base callback type that will be // managed by this callback class. The callback type is typically a - // interface class, which defines one or more virtual method prototypes + // interface class, which defines one or more virtual method prototypes // that users can override in subtypes. This type must be a derivative // of . - + typedef uvm_typed_callbacks#(T) super_type; typedef uvm_callbacks#(T,CB) this_type; @@ -532,14 +515,6 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) bit m_registered; - // UVM ! - static function void uvmt_drop_globals(); - m_tw_cb_q.delete(); - m_t_inst = null; - m_inst = null; - endfunction - // UVM ! - // get // --- @@ -549,7 +524,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) uvm_typeid_base cb_base_type; void'(super_type::m_initialize()); - + cb_base_type = uvm_typeid#(uvm_callback)::get(); m_cb_typeid = uvm_typeid#(CB)::get(); m_typeid = uvm_typeid#(T)::get(); @@ -560,7 +535,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) $cast(m_base_inst, m_inst); // The base inst in the super class gets set to this base inst m_t_inst = m_base_inst; - uvm_typeid_base::typeid_map[m_typeid] = m_inst; + uvm_typeid_base::typeid_map[m_typeid] = m_inst; uvm_typeid_base::type_map[m_b_inst] = m_typeid; end else begin @@ -591,7 +566,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) m_cb_typename = cbname; m_cb_typeid.typename = cbname; - inst.m_registered = 1; + inst.m_registered = 1; return 1; endfunction @@ -613,24 +588,23 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) // Function -- NODOCS -- add // // Registers the given callback object, ~cb~, with the given - // ~obj~ handle. The ~obj~ handle can be ~null~, which allows + // ~obj~ handle. The ~obj~ handle can be ~null~, which allows // registration of callbacks without an object context. If // ~ordering~ is UVM_APPEND (default), the callback will be executed // after previously added callbacks, else the callback // will be executed ahead of previously added callbacks. The ~cb~ // is the callback handle; it must be non-~null~, and if the callback // has already been added to the object instance then a warning is - // issued. Note that the CB parameter is optional. For example, the + // issued. Note that the CB parameter is optional. For example, the // following are equivalent: // //| uvm_callbacks#(my_comp)::add(comp_a, cb); //| uvm_callbacks#(my_comp, my_callback)::add(comp_a,cb); - // UVM ~ // @uvm-ieee 1800.2-2017 auto 10.7.2.3.1 static function void add(T obj, uvm_callback cb, uvm_apprepend ordering=UVM_APPEND); uvm_queue#(uvm_callback) q; - string nm,tnm; + string nm,tnm; void'(get()); @@ -707,18 +681,18 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) if(q.size() == 0) begin // Need to make sure that registered report catchers are added. This // way users don't need to set up uvm_report_object as a super type. -//UVM uvm_report_object o; -//UVM -//UVM if($cast(o,obj)) begin -//UVM uvm_queue#(uvm_callback) qr; -//UVM void'(uvm_callbacks#(uvm_report_object, uvm_callback)::get()); -//UVM qr = uvm_callbacks#(uvm_report_object,uvm_callback)::m_t_inst.m_tw_cb_q; -//UVM for(int i=0; i the CB parameter is - // optional. ~root~ specifies the location in the component hierarchy to start - // the search for ~name~. See for more details on searching + // Removes the given callback object, ~cb~, associated with one or more + // uvm_component callback queues. As with the CB parameter is + // optional. ~root~ specifies the location in the component hierarchy to start + // the search for ~name~. See for more details on searching // by name. // @uvm-ieee 1800.2-2017 auto 10.7.2.3.4 -//UVM static function void delete_by_name(string name, uvm_callback cb, -//UVM uvm_component root); -//UVM uvm_component cq[$]; -//UVM uvm_root top; -//UVM T t; -//UVM uvm_coreservice_t cs; -//UVM void'(get()); -//UVM cs = uvm_coreservice_t::get(); -//UVM top = cs.get_root(); -//UVM -//UVM `uvm_cb_trace_noobj(cb,$sformatf("Delete callback %0s by name from object(s) %0s ", -//UVM cb.get_name(), name)) -//UVM top.find_all(name,cq,root); -//UVM if(cq.size() == 0) begin -//UVM uvm_report_warning("CBNOMTC", { "delete_by_name failed to find any components matching the name ", -//UVM name, ", callback ", cb.get_name(), " will not be unregistered." }, UVM_NONE); -//UVM end -//UVM foreach(cq[i]) begin -//UVM if($cast(t,cq[i])) begin -//UVM delete(t,cb); -//UVM end -//UVM end -//UVM endfunction + static function void delete_by_name(string name, uvm_callback cb, + uvm_component root); + uvm_component cq[$]; + uvm_root top; + T t; + uvm_coreservice_t cs; + void'(get()); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + `uvm_cb_trace_noobj(cb,$sformatf("Delete callback %0s by name from object(s) %0s ", + cb.get_name(), name)) + top.find_all(name,cq,root); + if(cq.size() == 0) begin + uvm_report_warning("CBNOMTC", { "delete_by_name failed to find any components matching the name ", + name, ", callback ", cb.get_name(), " will not be unregistered." }, UVM_NONE); + end + foreach(cq[i]) begin + if($cast(t,cq[i])) begin + delete(t,cb); + end + end + endfunction //-------------------------- // Group -- NODOCS -- Iterator Interface @@ -866,7 +840,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) static function void m_get_q (ref uvm_queue #(uvm_callback) q, input T obj); if(!m_base_inst.m_pool.exists(obj)) begin //no instance specific q = (obj == null) ? m_t_inst.m_tw_cb_q : m_t_inst.m_get_tw_cb_q(obj); - end + end else begin q = m_base_inst.m_pool.get(obj); if(q==null) begin @@ -884,7 +858,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) // it will be updated with a value that can be supplied to to get the next // callback object. // - // If the queue is empty then ~null~ is returned. + // If the queue is empty then ~null~ is returned. // // The iterator class may be used as an alternative, simplified, // iterator interface. @@ -930,7 +904,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) // // Returns the next enabled callback of type CB which resides in the queue for ~obj~, // using ~itr~ as the starting point. If ~obj~ is ~null~ then the typewide queue for T - // is searched. ~itr~ is the iterator; it will be updated with a value that can be + // is searched. ~itr~ is the iterator; it will be updated with a value that can be // supplied to to get the next callback object. // // If no more callbacks exist in the queue, then ~null~ is returned. will @@ -957,7 +931,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) // // Returns the previous enabled callback of type CB which resides in the queue for ~obj~, // using ~itr~ as the starting point. If ~obj~ is ~null~ then the typewide queue for T - // is searched. ~itr~ is the iterator; it will be updated with a value that can be + // is searched. ~itr~ is the iterator; it will be updated with a value that can be // supplied to to get the previous callback object. // // If no more callbacks exist in the queue, then ~null~ is returned. will @@ -1006,7 +980,7 @@ class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) if ((obj == null) || (!m_pool.exists(obj))) begin // Only typewide callbacks exist - for (int qi=0; qi 2) && (match[0] == "/") && (match[match.len()-1] == "/"); + int len = match.len(); + + args.delete(); + foreach (m_argv[i]) begin + if ( match_is_regex && uvm_is_match( match, m_argv[i] ) ) begin + args.push_back( m_argv[i] ); + end + else if((m_argv[i].len() >= len) && (m_argv[i].substr(0,len - 1) == match)) begin + args.push_back(m_argv[i]); + end + end + + return args.size(); + endfunction + + + // Group -- NODOCS -- Argument Values + + // Function -- NODOCS -- get_arg_value + // + // This function finds the first argument which matches the ~match~ arg and + // returns the suffix of the argument. This is similar to the $value$plusargs + // system task, but does not take a formatting string. The return value is + // the number of command line arguments that match the ~match~ string, and + // ~value~ is the value of the first match. + + // @uvm-ieee 1800.2-2017 auto G.1.4.1 + function int get_arg_value (string match, ref string value); + int chars = match.len(); + get_arg_value = 0; + foreach (m_argv[i]) begin + if(m_argv[i].len() >= chars) begin + if(m_argv[i].substr(0,chars-1) == match) begin + get_arg_value++; + if(get_arg_value == 1) + value = m_argv[i].substr(chars,m_argv[i].len()-1); + end + end + end + endfunction + + // Function -- NODOCS -- get_arg_values + // + // This function finds all the arguments which matches the ~match~ arg and + // returns the suffix of the arguments in a list of values. The return + // value is the number of matches that were found (it is the same as + // values.size() ). + // For example if '+foo=1,yes,on +foo=5,no,off' was provided on the command + // line and the following code was executed: + // + //| string foo_values[$] + //| initial begin + //| void'(uvm_cmdline_proc.get_arg_values("+foo=",foo_values)); + //| + // + // The foo_values queue would contain two entries. These entries are shown + // here: + // + // 0 - "1,yes,on" + // 1 - "5,no,off" + // + // Splitting the resultant string is left to user but using the + // uvm_split_string() function is recommended. + + // @uvm-ieee 1800.2-2017 auto G.1.4.2 + function int get_arg_values (string match, ref string values[$]); + int chars = match.len(); + + values.delete(); + foreach (m_argv[i]) begin + if(m_argv[i].len() >= chars) begin + if(m_argv[i].substr(0,chars-1) == match) + values.push_back(m_argv[i].substr(chars,m_argv[i].len()-1)); + end + end + return values.size(); + endfunction + + // Group -- NODOCS -- Tool information + + // Function -- NODOCS -- get_tool_name + // + // Returns the simulation tool that is executing the simulation. + // This is a vendor specific string. + + function string get_tool_name (); + return uvm_dpi_get_tool_name(); + endfunction + + // Function -- NODOCS -- get_tool_version + // + // Returns the version of the simulation tool that is executing the simulation. + // This is a vendor specific string. + + function string get_tool_version (); + return uvm_dpi_get_tool_version(); + endfunction + + // constructor + + function new(string name = ""); + string s; + string sub; + int doInit=1; + super.new(name); + do begin + s = uvm_dpi_get_next_arg(doInit); + doInit=0; + if(s!="") begin + m_argv.push_back(s); + if(s[0] == "+") begin + m_plus_argv.push_back(s); + end + if(s.len() >= 4 && (s[0]=="-" || s[0]=="+")) begin + sub = s.substr(1,3); + sub = sub.toupper(); + if(sub == "UVM") + m_uvm_argv.push_back(s); + end + end + end while(s!=""); + + endfunction + + function bit m_convert_verb(string verb_str, output uvm_verbosity verb_enum); + case (verb_str) + "NONE" : begin verb_enum = UVM_NONE; return 1; end + "UVM_NONE" : begin verb_enum = UVM_NONE; return 1; end + "LOW" : begin verb_enum = UVM_LOW; return 1; end + "UVM_LOW" : begin verb_enum = UVM_LOW; return 1; end + "MEDIUM" : begin verb_enum = UVM_MEDIUM; return 1; end + "UVM_MEDIUM" : begin verb_enum = UVM_MEDIUM; return 1; end + "HIGH" : begin verb_enum = UVM_HIGH; return 1; end + "UVM_HIGH" : begin verb_enum = UVM_HIGH; return 1; end + "FULL" : begin verb_enum = UVM_FULL; return 1; end + "UVM_FULL" : begin verb_enum = UVM_FULL; return 1; end + "DEBUG" : begin verb_enum = UVM_DEBUG; return 1; end + "UVM_DEBUG" : begin verb_enum = UVM_DEBUG; return 1; end + default : begin return 0; end + endcase + endfunction + + + +endclass + diff --git a/test_regress/t/t_uvm/base/uvm_common_phases.svh b/test_regress/t/t_uvm/base/uvm_common_phases.svh new file mode 100644 index 0000000000..0f3273a07f --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_common_phases.svh @@ -0,0 +1,338 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2011 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2013 Cisco Systems, Inc. +// Copyright 2012 Accellera Systems Initiative +// Copyright 2018 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. +//---------------------------------------------------------------------- + +// Title -- NODOCS -- UVM Common Phases +// +// The common phases are the set of function and task phases that all +// s execute together. +// All s are always synchronized +// with respect to the common phases. +// +// The names of the UVM phases (which will be returned by get_name() for a +// phase instance) match the class names specified below with the "uvm_" +// and "_phase" removed. For example, the build phase corresponds to the +// uvm_build_phase class below and has the name "build", which means that +// the following can be used to call foo() at the end of the build phase +// (after all lower levels have finished build): +// +// | function void phase_ended(uvm_phase phase) ; +// | if (phase.get_name()=="build") foo() ; +// | endfunction +// +// The common phases are executed in the sequence they are specified below. +// +// +// Class -- NODOCS -- uvm_build_phase +// +// Create and configure of testbench structure +// +// that calls the +// method. +// +// Upon entry: +// - The top-level components have been instantiated under . +// - Current simulation time is still equal to 0 but some "delta cycles" may have occurred +// +// Typical Uses: +// - Instantiate sub-components. +// - Instantiate register model. +// - Get configuration values for the component being built. +// - Set configuration values for sub-components. +// +// Exit Criteria: +// - All s have been instantiated. + +// @uvm-ieee 1800.2-2017 auto 9.8.1.1 +class uvm_build_phase extends uvm_topdown_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.build_phase(phase); + endfunction + local static uvm_build_phase m_inst; + `uvm_type_name_decl("uvm_build_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + // + static function uvm_build_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="build"); + super.new(name); + endfunction +endclass + +// Class -- NODOCS -- uvm_connect_phase +// +// Establish cross-component connections. +// +// that calls the +// method. +// +// Upon Entry: +// - All components have been instantiated. +// - Current simulation time is still equal to 0 +// but some "delta cycles" may have occurred. +// +// Typical Uses: +// - Connect UVM TLM ports and exports. +// - Connect UVM TLM initiator sockets and target sockets. +// - Connect register model to adapter components. +// - Setup explicit phase domains. +// +// Exit Criteria: +// - All cross-component connections have been established. +// - All independent phase domains are set. +// + +// @uvm-ieee 1800.2-2017 auto 9.8.1.2 +class uvm_connect_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.connect_phase(phase); + endfunction + local static uvm_connect_phase m_inst; + `uvm_type_name_decl("uvm_connect_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_connect_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="connect"); + super.new(name); + endfunction +endclass + +// Class -- NODOCS -- uvm_end_of_elaboration_phase +// +// Fine-tune the testbench. +// +// that calls the +// method. +// +// Upon Entry: +// - The verification environment has been completely assembled. +// - Current simulation time is still equal to 0 +// but some "delta cycles" may have occurred. +// +// Typical Uses: +// - Display environment topology. +// - Open files. +// - Define additional configuration settings for components. +// +// Exit Criteria: +// - None. + +// @uvm-ieee 1800.2-2017 auto 9.8.1.3 +class uvm_end_of_elaboration_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.end_of_elaboration_phase(phase); + endfunction + local static uvm_end_of_elaboration_phase m_inst; + `uvm_type_name_decl("uvm_end_of_elaboration_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_end_of_elaboration_phase get(); + if(m_inst == null) begin + m_inst = new(); + end + return m_inst; + endfunction + protected function new(string name="end_of_elaboration"); + super.new(name); + endfunction +endclass + +// Class -- NODOCS -- uvm_start_of_simulation_phase +// +// Get ready for DUT to be simulated. +// +// that calls the +// method. +// +// Upon Entry: +// - Other simulation engines, debuggers, hardware assisted platforms and +// all other run-time tools have been started and synchronized. +// - The verification environment has been completely configured +// and is ready to start. +// - Current simulation time is still equal to 0 +// but some "delta cycles" may have occurred. +// +// Typical Uses: +// - Display environment topology +// - Set debugger breakpoint +// - Set initial run-time configuration values. +// +// Exit Criteria: +// - None. + + +// @uvm-ieee 1800.2-2017 auto 9.8.1.4 +class uvm_start_of_simulation_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.start_of_simulation_phase(phase); + endfunction + local static uvm_start_of_simulation_phase m_inst; + `uvm_type_name_decl("uvm_start_of_simulation_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_start_of_simulation_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="start_of_simulation"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.1.5 +class uvm_run_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.run_phase(phase); + endtask + local static uvm_run_phase m_inst; + `uvm_type_name_decl("uvm_run_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_run_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="run"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.1.6 +class uvm_extract_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.extract_phase(phase); + endfunction + local static uvm_extract_phase m_inst; + `uvm_type_name_decl("uvm_extract_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_extract_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="extract"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.1.7 +class uvm_check_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.check_phase(phase); + endfunction + local static uvm_check_phase m_inst; + `uvm_type_name_decl("uvm_check_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_check_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="check"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.1.8 +class uvm_report_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.report_phase(phase); + endfunction + local static uvm_report_phase m_inst; + `uvm_type_name_decl("uvm_report_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_report_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="report"); + super.new(name); + endfunction +endclass + + +// Class -- NODOCS -- uvm_final_phase +// +// Tie up loose ends. +// +// that calls the +// method. +// +// Upon Entry: +// - All test-related activity has completed. +// +// Typical Uses: +// - Close files. +// - Terminate co-simulation engines. +// +// Exit Criteria: +// - Ready to exit simulator. +// + +// @uvm-ieee 1800.2-2017 auto 9.8.1.9 +class uvm_final_phase extends uvm_topdown_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.final_phase(phase); + endfunction + local static uvm_final_phase m_inst; + `uvm_type_name_decl("uvm_final_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_final_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="final"); + super.new(name); + endfunction +endclass diff --git a/test_regress/t/t_uvm/base/uvm_comparer.svh b/test_regress/t/t_uvm/base/uvm_comparer.svh new file mode 100644 index 0000000000..d15fae4cfc --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_comparer.svh @@ -0,0 +1,692 @@ +//----------------------------------------------------------------------------- +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, Inc. +// Copyright 2018 Qualcomm, Inc. +// Copyright 2014 Intel Corporation +// Copyright 2013-2018 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_comparer +// +// The uvm_comparer class provides a policy object for doing comparisons. The +// policies determine how miscompares are treated and counted. Results of a +// comparison are stored in the comparer object. The +// and methods are passed a uvm_comparer policy +// object. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 16.3.1 +class uvm_comparer extends uvm_policy; + + // @uvm-ieee 1800.2-2017 auto 16.3.2.3 + `uvm_object_utils(uvm_comparer) + + // @uvm-ieee 1800.2-2017 auto 16.3.2.2 + extern virtual function void flush(); + + // @uvm-ieee 1800.2-2017 auto 16.3.3.5 + extern virtual function uvm_policy::recursion_state_e object_compared( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion, + output bit ret_val + ); + + // @uvm-ieee 1800.2-2017 auto 16.3.3.8 + extern virtual function string get_miscompares(); + + extern virtual function int unsigned get_result(); + + extern virtual function void set_result(int unsigned result) ; + + // @uvm-ieee 1800.2-2017 auto 16.3.4.1 + extern virtual function void set_recursion_policy( uvm_recursion_policy_enum policy); + + // @uvm-ieee 1800.2-2017 auto 16.3.4.1 + extern virtual function uvm_recursion_policy_enum get_recursion_policy(); + + // @uvm-ieee 1800.2-2017 auto 16.3.4.2 + extern virtual function void set_check_type( bit enabled ); + + // @uvm-ieee 1800.2-2017 auto 16.3.4.2 + extern virtual function bit get_check_type(); + + // @uvm-ieee 1800.2-2017 auto 16.3.5.1 + extern virtual function void set_show_max (int unsigned show_max); + + extern virtual function int unsigned get_show_max (); + + // @uvm-ieee 1800.2-2017 auto 16.3.5.2 + extern virtual function void set_verbosity (int unsigned verbosity); + + extern virtual function int unsigned get_verbosity (); + + // @uvm-ieee 1800.2-2017 auto 16.3.5.3 + extern virtual function void set_severity (uvm_severity severity); + + // @uvm-ieee 1800.2-2017 auto 16.3.5.3 + extern virtual function uvm_severity get_severity (); + + // @uvm-ieee 1800.2-2017 auto 16.3.6 + extern virtual function void set_threshold (int unsigned threshold); + + extern virtual function int unsigned get_threshold (); + + typedef struct { + recursion_state_e state; + bit ret_val; + } state_info_t ; + state_info_t m_recur_states[uvm_object /*LHS*/][uvm_object /*RHS*/][uvm_recursion_policy_enum /*recursion*/]; + + // Variable -- NODOCS -- policy + // + // Determines whether comparison is UVM_DEEP, UVM_REFERENCE, or UVM_SHALLOW. + +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; +`else + local uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; +`endif + + // Variable -- NODOCS -- show_max + // + // Sets the maximum number of messages to send to the printer for miscompares + // of an object. + +`ifdef UVM_ENABLE_DEPRECATED_API + int unsigned show_max = 1; +`else + local int unsigned show_max = 1; +`endif + + // Variable -- NODOCS -- verbosity + // + // Sets the verbosity for printed messages. + // + // The verbosity setting is used by the messaging mechanism to determine + // whether messages should be suppressed or shown. + +`ifdef UVM_ENABLE_DEPRECATED_API + int unsigned verbosity = UVM_LOW; +`else + local int unsigned verbosity = UVM_LOW; +`endif + + + // Variable -- NODOCS -- sev + // + // Sets the severity for printed messages. + // + // The severity setting is used by the messaging mechanism for printing and + // filtering messages. + +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_severity sev = UVM_INFO; +`else + local uvm_severity sev = UVM_INFO; +`endif + + + // Variable -- NODOCS -- miscompares + // + // This string is reset to an empty string when a comparison is started. + // + // The string holds the last set of miscompares that occurred during a + // comparison. + +`ifdef UVM_ENABLE_DEPRECATED_API + string miscompares = ""; +`else + local string miscompares = ""; +`endif + + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- physical + // + // This bit provides a filtering mechanism for fields. + // + // The abstract and physical settings allow an object to distinguish between + // two different classes of fields. + // + // It is up to you, in the method, to test the + // setting of this field if you want to use the physical trait as a filter. + + bit physical = 1; +`endif + + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- abstract + // + // This bit provides a filtering mechanism for fields. + // + // The abstract and physical settings allow an object to distinguish between + // two different classes of fields. + // + // It is up to you, in the method, to test the + // setting of this field if you want to use the abstract trait as a filter. + + bit abstract = 1; +`endif + + // Variable -- NODOCS -- check_type + // + // This bit determines whether the type, given by , + // is used to verify that the types of two objects are the same. + // + // This bit is used by the method. In some cases it is useful + // to set this to 0 when the two operands are related by inheritance but are + // different types. + +`ifdef UVM_ENABLE_DEPRECATED_API + bit check_type = 1; +`else + local bit check_type = 1; +`endif + + + // Variable -- NODOCS -- result + // + // This bit stores the number of miscompares for a given compare operation. + // You can use the result to determine the number of miscompares that + // were found. + +`ifdef UVM_ENABLE_DEPRECATED_API + int unsigned result = 0; +`else + local int unsigned result = 0; +`endif + + local int unsigned m_threshold; + + // @uvm-ieee 1800.2-2017 auto 16.3.2.1 + function new(string name=""); + super.new(name); + m_threshold = 1; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 16.3.2.4 + static function void set_default (uvm_comparer comparer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_comparer(comparer) ; + endfunction + + // @uvm-ieee 1800.2-2017 auto 16.3.2.5 + static function uvm_comparer get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_comparer() ; + endfunction + + + // Function -- NODOCS -- compare_field + // + // Compares two integral values. + // + // The ~name~ input is used for purposes of storing and printing a miscompare. + // + // The left-hand-side ~lhs~ and right-hand-side ~rhs~ objects are the two + // objects used for comparison. + // + // The size variable indicates the number of bits to compare; size must be + // less than or equal to 4096. + // + // The radix is used for reporting purposes, the default radix is hex. + + // @uvm-ieee 1800.2-2017 auto 16.3.3.1 + virtual function bit compare_field (string name, + uvm_bitstream_t lhs, + uvm_bitstream_t rhs, + int size, + uvm_radix_enum radix=UVM_NORADIX); + uvm_bitstream_t mask; + string msg; + + if(size <= 64) + return compare_field_int(name, lhs, rhs, size, radix); + + mask = -1; + mask >>= (UVM_STREAMBITS-size); + if((lhs & mask) !== (rhs & mask)) begin + case (radix) + UVM_BIN: begin + $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", + name, lhs&mask, rhs&mask); + end + UVM_OCT: begin + $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", + name, lhs&mask, rhs&mask); + end + UVM_DEC: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + UVM_TIME: begin + $swrite(msg, "%s: lhs = %0t : rhs = %0t", + name, lhs&mask, rhs&mask); + end + UVM_STRING: begin + $swrite(msg, "%s: lhs = %0s : rhs = %0s", + name, lhs&mask, rhs&mask); + end + UVM_ENUM: begin + //Printed as decimal, user should cuse compare string for enum val + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + default: begin + $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", + name, lhs&mask, rhs&mask); + end + endcase + print_msg(msg); + return 0; + end + return 1; + endfunction + + + + // Function -- NODOCS -- compare_field_int + // + // This method is the same as except that the arguments are + // small integers, less than or equal to 64 bits. It is automatically called + // by if the operand size is less than or equal to 64. + + // @uvm-ieee 1800.2-2017 auto 16.3.3.2 + virtual function bit compare_field_int (string name, + uvm_integral_t lhs, + uvm_integral_t rhs, + int size, + uvm_radix_enum radix=UVM_NORADIX); + logic [63:0] mask; + string msg; + + mask = -1; + mask >>= (64-size); + if((lhs & mask) !== (rhs & mask)) begin + case (radix) + UVM_BIN: begin + $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", + name, lhs&mask, rhs&mask); + end + UVM_OCT: begin + $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", + name, lhs&mask, rhs&mask); + end + UVM_DEC: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + UVM_TIME: begin + $swrite(msg, "%s: lhs = %0t : rhs = %0t", + name, lhs&mask, rhs&mask); + end + UVM_STRING: begin + $swrite(msg, "%s: lhs = %0s : rhs = %0s", + name, lhs&mask, rhs&mask); + end + UVM_ENUM: begin + //Printed as decimal, user should cuse compare string for enum val + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + default: begin + $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", + name, lhs&mask, rhs&mask); + end + endcase + print_msg(msg); + return 0; + end + return 1; + endfunction + + + // Function -- NODOCS -- compare_field_real + // + // This method is the same as except that the arguments are + // real numbers. + + // @uvm-ieee 1800.2-2017 auto 16.3.3.3 + virtual function bit compare_field_real (string name, + real lhs, + real rhs); + string msg; + + if(lhs != rhs) begin + $swrite(msg, name, ": lhs = ", lhs, " : rhs = ", rhs); + print_msg(msg); + return 0; + end + return 1; + endfunction + + // Stores the passed-in names of the objects in the hierarchy + local string m_object_names[$]; + local function string m_current_context(string name=""); + if (m_object_names.size() == 0) + return name; //?? + else if ((m_object_names.size() == 1) && (name=="")) + return m_object_names[0]; + else begin + string full_name; + foreach(m_object_names[i]) begin + if (i == m_object_names.size() - 1) + full_name = {full_name, m_object_names[i]}; + else + full_name = {full_name, m_object_names[i], "."}; + end + if (name != "") + return {full_name, ".", name}; + else + return full_name; + end + endfunction : m_current_context + + // Function -- NODOCS -- compare_object + // + // Compares two class objects using the knob to determine whether the + // comparison should be deep, shallow, or reference. + // + // The name input is used for purposes of storing and printing a miscompare. + // + // The ~lhs~ and ~rhs~ objects are the two objects used for comparison. + // + // The ~check_type~ determines whether or not to verify the object + // types match (the return from ~lhs.get_type_name()~ matches + // ~rhs.get_type_name()~). + + // @uvm-ieee 1800.2-2017 auto 16.3.3.4 + virtual function bit compare_object (string name, + uvm_object lhs, + uvm_object rhs); + int old_result ; + uvm_field_op field_op ; + uvm_policy::recursion_state_e prev_state; + bit ret_val = 1; + + // Fast Pass + if (rhs == lhs) + return ret_val; + + // Push the name on the stack + m_object_names.push_back(name); + + // Reference Fail + if (policy == UVM_REFERENCE && lhs != rhs) begin + print_msg_object(lhs, rhs); + ret_val = 0; + end + + // Fast fail on null + if (ret_val && (rhs == null || lhs == null)) begin + print_msg_object(lhs, rhs); + // if ((get_active_object_depth() == 0) && (lhs != null)) begin + // uvm_report_info("MISCMP", + // $sformatf("%0d Miscompare(s) for object %s@%0d vs. null", + // result, + // lhs.get_name(), + // lhs.get_inst_id()), + // get_verbosity()); + // end + ret_val = 0; + end + + // Hierarchical comparison + if (ret_val) begin + // Warn on possible infinite loop + prev_state = object_compared(lhs,rhs,get_recursion_policy(),ret_val); + if (prev_state != uvm_policy::NEVER) // + `uvm_warning("UVM/COPIER/LOOP", {"Possible loop when comparing '", + lhs.get_full_name(), "' to '", rhs.get_full_name(), "'"}) + + + push_active_object(lhs); + m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::STARTED,0}; + old_result = get_result(); + + // Check typename + // Implemented as if Mantis 6602 was accepted + if (get_check_type() && (lhs.get_object_type() != rhs.get_object_type())) begin + if(lhs.get_type_name() != rhs.get_type_name()) begin + print_msg({"type: lhs = \"", lhs.get_type_name(), "\" : rhs = \"", rhs.get_type_name(), "\""}); + end + else begin + print_msg({"get_object_type() for ",lhs.get_name()," does not match get_object_type() for ",rhs.get_name()}); + end + end + + field_op = uvm_field_op::m_get_available_op(); + field_op.set(UVM_COMPARE,this,rhs); + lhs.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + ret_val = lhs.do_compare(rhs,this); + end + field_op.m_recycle(); + + // If do_compare() returned 1, check for a change + // in the result count. + if (ret_val && (get_result() > old_result)) + ret_val = 0; + + // Save off the comparison result + m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::FINISHED,ret_val}; + void'(pop_active_object()); + end // if (ret_val) + + // Pop the name off the stack + void'(m_object_names.pop_back()); + + // Only emit a message on a miscompare, and only if + // we're at the top level + if (!ret_val && (get_active_object_depth() == 0)) begin + string msg ; + + // If there are stored results + if(get_result()) begin + // If there's a display limit that we've hit + if (get_show_max() && (get_show_max() < get_result())) + $swrite(msg, "%0d Miscompare(s) (%0d shown) for object ", + result, show_max); + // Else there's either no limit, or we didn't hit it + else + $swrite(msg, "%0d Miscompare(s) for object ", result); + end + + uvm_pkg::uvm_report(sev, "MISCMP", $sformatf("%s%s@%0d vs. %s@%0d", msg, + (lhs == null) ? "" : lhs.get_name(), + (lhs == null) ? 0 : lhs.get_inst_id(), + (rhs == null) ? "" : rhs.get_name(), + (rhs == null) ? 0 : rhs.get_inst_id()), + get_verbosity(), `uvm_file, `uvm_line); + + end // if (!ret_val && (get_active_object_depth() == 1)) + + return ret_val; + endfunction + + + // Function -- NODOCS -- compare_string + // + // Compares two string variables. + // + // The ~name~ input is used for purposes of storing and printing a miscompare. + // + // The ~lhs~ and ~rhs~ objects are the two objects used for comparison. + + // @uvm-ieee 1800.2-2017 auto 16.3.3.6 + virtual function bit compare_string (string name, + string lhs, + string rhs); + string msg; + if(lhs != rhs) begin + msg = { name, ": lhs = \"", lhs, "\" : rhs = \"", rhs, "\""}; + print_msg(msg); + return 0; + end + return 1; + endfunction + + + // Function -- NODOCS -- print_msg + // + // Causes the error count to be incremented and the message, ~msg~, to be + // appended to the string (a newline is used to separate + // messages). + // + // If the message count is less than the setting, then the message + // is printed to standard-out using the current verbosity and severity + // settings. See the and variables for more information. + + // @uvm-ieee 1800.2-2017 auto 16.3.3.7 + function void print_msg (string msg); + + string tmp = m_current_context(msg); + result++; + if((get_show_max() == 0) || + (get_result() <= get_show_max())) begin + msg = {"Miscompare for ", tmp}; + uvm_pkg::uvm_report(sev, "MISCMP", msg, get_verbosity(), `uvm_file, `uvm_line); + end + miscompares = { miscompares, tmp, "\n" }; + endfunction + + + + // Internal methods - do not call directly + + // print_msg_object + // ---------------- + + function void print_msg_object(uvm_object lhs, uvm_object rhs); + string tmp = $sformatf("%s: lhs = @%0d : rhs = @%0d", + m_current_context(), + (lhs != null ? lhs.get_inst_id() : 0), + (rhs != null ? rhs.get_inst_id() : 0)); + result++; + + if((get_show_max() == 0) || + (get_result() <= get_show_max())) begin + uvm_pkg::uvm_report(sev, + "MISCMP", + {"Miscompare for ", tmp}, + get_verbosity(), + `uvm_file, + `uvm_line); + end + + miscompares = { miscompares, tmp, "\n" }; + endfunction + + int depth; //current depth of objects + bit compare_map[uvm_object][uvm_object]; + +endclass + +function void uvm_comparer::flush(); + miscompares = "" ; + check_type = 1 ; + result = 0 ; + m_recur_states.delete(); +endfunction + +function uvm_policy::recursion_state_e uvm_comparer::object_compared( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion, + output bit ret_val +); + if (!m_recur_states.exists(lhs)) return NEVER ; + else if (!m_recur_states[lhs].exists(rhs)) return NEVER ; + else if (!m_recur_states[lhs][rhs].exists(recursion)) return NEVER ; + else begin + if (m_recur_states[lhs][rhs][recursion].state == FINISHED) + ret_val = m_recur_states[lhs][rhs][recursion].ret_val; + return m_recur_states[lhs][rhs][recursion].state ; + end +endfunction + +function string uvm_comparer::get_miscompares(); + return miscompares ; +endfunction + +function int unsigned uvm_comparer::get_result(); + return result ; +endfunction + +function void uvm_comparer::set_result(int unsigned result); + this.result = result ; +endfunction + +function void uvm_comparer::set_recursion_policy( uvm_recursion_policy_enum policy); + this.policy = policy ; +endfunction + +function uvm_recursion_policy_enum uvm_comparer::get_recursion_policy(); + return policy ; +endfunction + +function void uvm_comparer::set_check_type( bit enabled ); + check_type = enabled ; +endfunction + +function bit uvm_comparer::get_check_type(); + return check_type ; +endfunction + +function void uvm_comparer::set_show_max (int unsigned show_max); + this.show_max = show_max ; +endfunction + +function int unsigned uvm_comparer::get_show_max(); + return show_max ; +endfunction + +function void uvm_comparer::set_verbosity (int unsigned verbosity); + this.verbosity = verbosity ; +endfunction + +function int unsigned uvm_comparer::get_verbosity(); + return verbosity ; +endfunction + +function void uvm_comparer::set_severity (uvm_severity severity); + sev = severity ; +endfunction + +function uvm_severity uvm_comparer::get_severity(); + return sev ; +endfunction + +function void uvm_comparer::set_threshold (int unsigned threshold); + m_threshold = threshold; +endfunction + +function int unsigned uvm_comparer::get_threshold(); + return m_threshold; +endfunction + diff --git a/test_regress/t/t_uvm/base/uvm_component.svh b/test_regress/t/t_uvm/base/uvm_component.svh index 0109a6f784..24fe542965 100644 --- a/test_regress/t/t_uvm/base/uvm_component.svh +++ b/test_regress/t/t_uvm/base/uvm_component.svh @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 // //------------------------------------------------------------------------------ // Copyright 2010 Paradigm Works @@ -29,392 +28,3308 @@ // permissions and limitations under the License. //------------------------------------------------------------------------------ -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- +typedef class uvm_objection; +typedef class uvm_sequence_base; +typedef class uvm_sequence_item; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_component +// +// The uvm_component class is the root base class for UVM components. In +// addition to the features inherited from and , +// uvm_component provides the following interfaces: +// +// Hierarchy - provides methods for searching and traversing the component +// hierarchy. +// +// Phasing - defines a phased test flow that all components follow, with a +// group of standard phase methods and an API for custom phases and +// multiple independent phasing domains to mirror DUT behavior e.g. power +// +// Reporting - provides a convenience interface to the . All +// messages, warnings, and errors are processed through this interface. +// +// Transaction recording - provides methods for recording the transactions +// produced or consumed by the component to a transaction database (vendor +// specific). +// +// Factory - provides a convenience interface to the . The factory +// is used to create new components and other objects based on type-wide and +// instance-specific configuration. +// +// The uvm_component is automatically seeded during construction using UVM +// seeding, if enabled. All other objects must be manually reseeded, if +// appropriate. See for more information. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.1.1 +virtual class uvm_component extends uvm_report_object; + + // Function -- NODOCS -- new + // + // Creates a new component with the given leaf instance ~name~ and handle + // to its ~parent~. If the component is a top-level component (i.e. it is + // created in a static module or interface), ~parent~ should be ~null~. + // + // The component will be inserted as a child of the ~parent~ object, if any. + // If ~parent~ already has a child by the given ~name~, an error is produced. + // + // If ~parent~ is ~null~, then the component will become a child of the + // implicit top-level component, ~uvm_top~. + // + // All classes derived from uvm_component must call super.new(name,parent). + + // @uvm-ieee 1800.2-2017 auto 13.1.2.1 + extern function new (string name, uvm_component parent); + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Hierarchy Interface + //---------------------------------------------------------------------------- + // + // These methods provide user access to information about the component + // hierarchy, i.e., topology. + // + //---------------------------------------------------------------------------- + + // Function -- NODOCS -- get_parent + // + // Returns a handle to this component's parent, or ~null~ if it has no parent. + + // @uvm-ieee 1800.2-2017 auto 13.1.3.1 + extern virtual function uvm_component get_parent (); + + + // Function -- NODOCS -- get_full_name + // + // Returns the full hierarchical name of this object. The default + // implementation concatenates the hierarchical name of the parent, if any, + // with the leaf name of this object, as given by . + + // @uvm-ieee 1800.2-2017 auto 13.1.3.2 + extern virtual function string get_full_name (); + + + // Function -- NODOCS -- get_children + // + // This function populates the end of the ~children~ array with the + // list of this component's children. + // + //| uvm_component array[$]; + //| my_comp.get_children(array); + //| foreach(array[i]) + //| do_something(array[i]); + + // @uvm-ieee 1800.2-2017 auto 13.1.3.3 + extern function void get_children(ref uvm_component children[$]); + + + + // @uvm-ieee 1800.2-2017 auto 13.1.3.4 + extern function uvm_component get_child (string name); + + + // @uvm-ieee 1800.2-2017 auto 13.1.3.4 + extern function int get_next_child (ref string name); + + // Function -- NODOCS -- get_first_child + // + // These methods are used to iterate through this component's children, if + // any. For example, given a component with an object handle, ~comp~, the + // following code calls for each child: + // + //| string name; + //| uvm_component child; + //| if (comp.get_first_child(name)) + //| do begin + //| child = comp.get_child(name); + //| child.print(); + //| end while (comp.get_next_child(name)); + + // @uvm-ieee 1800.2-2017 auto 13.1.3.4 + extern function int get_first_child (ref string name); + + + // Function -- NODOCS -- get_num_children + // + // Returns the number of this component's children. + + // @uvm-ieee 1800.2-2017 auto 13.1.3.5 + extern function int get_num_children (); + + + // Function -- NODOCS -- has_child + // + // Returns 1 if this component has a child with the given ~name~, 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 13.1.3.6 + extern function int has_child (string name); + + + // Function - set_name + // + // Renames this component to ~name~ and recalculates all descendants' + // full names. This is an internal function for now. + + extern virtual function void set_name (string name); + + + // Function -- NODOCS -- lookup + // + // Looks for a component with the given hierarchical ~name~ relative to this + // component. If the given ~name~ is preceded with a '.' (dot), then the search + // begins relative to the top level (absolute lookup). The handle of the + // matching component is returned, else ~null~. The name must not contain + // wildcards. + + // @uvm-ieee 1800.2-2017 auto 13.1.3.7 + extern function uvm_component lookup (string name); + + + // Function -- NODOCS -- get_depth + // + // Returns the component's depth from the root level. uvm_top has a + // depth of 0. The test and any other top level components have a depth + // of 1, and so on. + + extern function int unsigned get_depth(); + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Phasing Interface + //---------------------------------------------------------------------------- + // + // These methods implement an interface which allows all components to step + // through a standard schedule of phases, or a customized schedule, and + // also an API to allow independent phase domains which can jump like state + // machines to reflect behavior e.g. power domains on the DUT in different + // portions of the testbench. The phase tasks and functions are the phase + // name with the _phase suffix. For example, the build phase function is + // . + // + // All processes associated with a task-based phase are killed when the phase + // ends. See for more details. + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- build_phase + // + // The phase implementation method. + // + // Any override should call super.build_phase(phase) to execute the automatic + // configuration of fields registered in the component by calling + // . + // To turn off automatic configuration for a component, + // do not call super.build_phase(phase). + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.1 + extern virtual function void build_phase(uvm_phase phase); + + // Function -- NODOCS -- connect_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.2 + extern virtual function void connect_phase(uvm_phase phase); + + // Function -- NODOCS -- end_of_elaboration_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.3 + extern virtual function void end_of_elaboration_phase(uvm_phase phase); + + // Function -- NODOCS -- start_of_simulation_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.4 + extern virtual function void start_of_simulation_phase(uvm_phase phase); + + // Task -- NODOCS -- run_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // Thus the phase will automatically + // end once all objections are dropped using ~phase.drop_objection()~. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // The run_phase task should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.5 + extern virtual task run_phase(uvm_phase phase); + + // Task -- NODOCS -- pre_reset_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.1 + extern virtual task pre_reset_phase(uvm_phase phase); + + // Task -- NODOCS -- reset_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.2 + extern virtual task reset_phase(uvm_phase phase); + + // Task -- NODOCS -- post_reset_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.3 + extern virtual task post_reset_phase(uvm_phase phase); + + // Task -- NODOCS -- pre_configure_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.4 + extern virtual task pre_configure_phase(uvm_phase phase); + + // Task -- NODOCS -- configure_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.5 + extern virtual task configure_phase(uvm_phase phase); + + // Task -- NODOCS -- post_configure_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.6 + extern virtual task post_configure_phase(uvm_phase phase); + + // Task -- NODOCS -- pre_main_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.7 + extern virtual task pre_main_phase(uvm_phase phase); + + // Task -- NODOCS -- main_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.8 + extern virtual task main_phase(uvm_phase phase); + + // Task -- NODOCS -- post_main_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.9 + extern virtual task post_main_phase(uvm_phase phase); + + // Task -- NODOCS -- pre_shutdown_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.10 + extern virtual task pre_shutdown_phase(uvm_phase phase); + + // Task -- NODOCS -- shutdown_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.11 + extern virtual task shutdown_phase(uvm_phase phase); + + // Task -- NODOCS -- post_shutdown_phase + // + // The phase implementation method. + // + // This task returning or not does not indicate the end + // or persistence of this phase. + // It is necessary to raise an objection + // using ~phase.raise_objection()~ to cause the phase to persist. + // Once all components have dropped their respective objection + // using ~phase.drop_objection()~, or if no components raises an + // objection, the phase is ended. + // + // Any processes forked by this task continue to run + // after the task returns, + // but they will be killed once the phase ends. + // + // This method should not be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.2.12 + extern virtual task post_shutdown_phase(uvm_phase phase); + + // Function -- NODOCS -- extract_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.6 + extern virtual function void extract_phase(uvm_phase phase); + + + + // Function -- NODOCS -- check_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.7 + extern virtual function void check_phase(uvm_phase phase); + + // Function -- NODOCS -- report_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.8 + extern virtual function void report_phase(uvm_phase phase); + + // Function -- NODOCS -- final_phase + // + // The phase implementation method. + // + // This method should never be called directly. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.1.9 + extern virtual function void final_phase(uvm_phase phase); + +`ifdef UVM_ENABLE_DEPRECATED_API + // For backward compatibility the base method calls . + extern virtual function void build(); + + // For backward compatibility the base connect_phase method calls connect. + extern virtual function void connect(); + + // For backward compatibility the base method calls . + extern virtual function void end_of_elaboration(); + + // For backward compatibility the base method calls . + extern virtual function void start_of_simulation(); + + // For backward compatibility the base method calls . + extern virtual task run(); + + // For backward compatibility the base extract_phase method calls extract. + extern virtual function void extract(); + + // For backward compatibility the base check_phase method calls check. + extern virtual function void check(); + + // For backward compatibility the base report_phase method calls report. + extern virtual function void report(); +`endif // UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- phase_started + // + // Invoked at the start of each phase. The ~phase~ argument specifies + // the phase being started. Any threads spawned in this callback are + // not affected when the phase ends. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.3.1 + extern virtual function void phase_started (uvm_phase phase); + + // Function -- NODOCS -- phase_ready_to_end + // + // Invoked when all objections to ending the given ~phase~ and all + // sibling phases have been dropped, thus indicating that ~phase~ is + // ready to begin a clean exit. Sibling phases are any phases that + // have a common successor phase in the schedule plus any phases that + // sync'd to the current phase. Components needing to consume delta + // cycles or advance time to perform a clean exit from the phase + // may raise the phase's objection. + // + // |phase.raise_objection(this,"Reason"); + // + // It is the responsibility of this component to drop the objection + // once it is ready for this phase to end (and processes killed). + // If no objection to the given ~phase~ or sibling phases are raised, + // then phase_ended() is called after a delta cycle. If any objection + // is raised, then when all objections to ending the given ~phase~ + // and siblings are dropped, another iteration of phase_ready_to_end + // is called. To prevent endless iterations due to coding error, + // after 20 iterations, phase_ended() is called regardless of whether + // previous iteration had any objections raised. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.3.2 + extern virtual function void phase_ready_to_end (uvm_phase phase); + + + // Function -- NODOCS -- phase_ended + // + // Invoked at the end of each phase. The ~phase~ argument specifies + // the phase that is ending. Any threads spawned in this callback are + // not affected when the phase ends. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.3.3 + extern virtual function void phase_ended (uvm_phase phase); + + + //-------------------------------------------------------------------- + // phase / schedule / domain API + //-------------------------------------------------------------------- + + + // Function -- NODOCS -- set_domain + // + // Apply a phase domain to this component and, if ~hier~ is set, + // recursively to all its children. + // + // Calls the virtual method, which derived components can + // override to augment or replace the domain definition of its base class. + // + + // @uvm-ieee 1800.2-2017 auto 13.1.4.4.1 + extern function void set_domain(uvm_domain domain, int hier=1); + + + // Function -- NODOCS -- get_domain + // + // Return handle to the phase domain set on this component + + // @uvm-ieee 1800.2-2017 auto 13.1.4.4.2 + extern function uvm_domain get_domain(); + + + // Function -- NODOCS -- define_domain + // + // Builds custom phase schedules into the provided ~domain~ handle. + // + // This method is called by , which integrators use to specify + // this component belongs in a domain apart from the default 'uvm' domain. + // + // Custom component base classes requiring a custom phasing schedule can + // augment or replace the domain definition they inherit by overriding + // their ~defined_domain~. To augment, overrides would call super.define_domain(). + // To replace, overrides would not call super.define_domain(). + // + // The default implementation adds a copy of the ~uvm~ phasing schedule to + // the given ~domain~, if one doesn't already exist, and only if the domain + // is currently empty. + // + // Calling + // with the default ~uvm~ domain (i.e. ) on + // a component with no ~define_domain~ override effectively reverts the + // that component to using the default ~uvm~ domain. This may be useful + // if a branch of the testbench hierarchy defines a custom domain, but + // some child sub-branch should remain in the default ~uvm~ domain, + // call with a new domain instance handle with ~hier~ set. + // Then, in the sub-branch, call with the default ~uvm~ domain handle, + // obtained via . + // + // Alternatively, the integrator may define the graph in a new domain externally, + // then call to apply it to a component. + + + // @uvm-ieee 1800.2-2017 auto 13.1.4.4.3 + extern virtual protected function void define_domain(uvm_domain domain); + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- set_phase_imp + // + // Override the default implementation for a phase on this component (tree) with a + // custom one, which must be created as a singleton object extending the default + // one and implementing required behavior in exec and traverse methods + // + // The ~hier~ specifies whether to apply the custom functor to the whole tree or + // just this component. + + extern function void set_phase_imp(uvm_phase phase, uvm_phase imp, int hier=1); +`endif + + // Task -- NODOCS -- suspend + // + // Suspend this component. + // + // This method must be implemented by the user to suspend the + // component according to the protocol and functionality it implements. + // A suspended component can be subsequently resumed using . + + // @uvm-ieee 1800.2-2017 auto 13.1.4.5.1 + extern virtual task suspend (); + + + // Task -- NODOCS -- resume + // + // Resume this component. + // + // This method must be implemented by the user to resume a component + // that was previously suspended using . + // Some component may start in the suspended state and + // may need to be explicitly resumed. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.5.2 + extern virtual task resume (); + + + // Function -- NODOCS -- resolve_bindings + // + // Processes all port, export, and imp connections. Checks whether each port's + // min and max connection requirements are met. + // + // It is called just before the end_of_elaboration phase. + // + // Users should not call directly. + + extern virtual function void resolve_bindings (); + + extern function string massage_scope(string scope); + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Configuration Interface + //---------------------------------------------------------------------------- + // + // Components can be designed to be user-configurable in terms of its + // topology (the type and number of children it has), mode of operation, and + // run-time parameters (knobs). The configuration interface accommodates + // this common need, allowing component composition and state to be modified + // without having to derive new classes or new class hierarchies for + // every configuration scenario. + // + //---------------------------------------------------------------------------- + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- check_config_usage + // + // Check all configuration settings in a components configuration table + // to determine if the setting has been used, overridden or not used. + // When ~recurse~ is 1 (default), configuration for this and all child + // components are recursively checked. This function is automatically + // called in the check phase, but can be manually called at any time. + // + // To get all configuration information prior to the run phase, do something + // like this in your top object: + //| function void start_of_simulation_phase(uvm_phase phase); + //| check_config_usage(); + //| endfunction + + extern function void check_config_usage (bit recurse=1); +`endif // UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- apply_config_settings + // + // Searches for all config settings matching this component's instance path. + // For each match, the appropriate set_*_local method is called using the + // matching config setting's field_name and value. Provided the set_*_local + // method is implemented, the component property associated with the + // field_name is assigned the given value. + // + // This function is called by . + // + // The apply_config_settings method determines all the configuration + // settings targeting this component and calls the appropriate set_*_local + // method to set each one. To work, you must override one or more set_*_local + // methods to accommodate setting of your component's specific properties. + // Any properties registered with the optional `uvm_*_field macros do not + // require special handling by the set_*_local methods; the macros provide + // the set_*_local functionality for you. + // + // If you do not want apply_config_settings to be called for a component, + // then the build_phase() method should be overloaded and you should not call + // super.build_phase(phase). Likewise, apply_config_settings can be overloaded to + // customize automated configuration. + // + // When the ~verbose~ bit is set, all overrides are printed as they are + // applied. If the component's property is set, then + // apply_config_settings is automatically called with ~verbose~ = 1. + + // @uvm-ieee 1800.2-2017 auto 13.1.5.1 + extern virtual function void apply_config_settings (bit verbose = 0); + + // Function -- NODOCS -- use_automatic_config + // + // Returns 1 if the component should call in the ; + // otherwise, returns 0. + // + // @uvm-ieee 1800.2-2017 auto 13.1.5.2 + extern virtual function bit use_automatic_config(); + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- print_config_settings + // + // Called without arguments, print_config_settings prints all configuration + // information for this component, as set by previous calls to . + // The settings are printing in the order of their precedence. + // + // If ~field~ is specified and non-empty, then only configuration settings + // matching that field, if any, are printed. The field may not contain + // wildcards. + // + // If ~comp~ is specified and non-~null~, then the configuration for that + // component is printed. + // + // If ~recurse~ is set, then configuration information for all ~comp~'s + // children and below are printed as well. + // + // This function has been deprecated. Use print_config instead. + + extern function void print_config_settings (string field="", + uvm_component comp=null, + bit recurse=0); +`endif // UVM_ENABLE_DEPRECATED_API + + // Function: print_config + // + // Print_config prints all configuration information for this + // component, as set by previous calls to and exports to + // the resources pool. The settings are printed in the order of + // their precedence. + // + // If ~recurse~ is set, then configuration information for all + // children and below are printed as well. + // + // if ~audit~ is set then the audit trail for each resource is printed + // along with the resource name and value + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + extern function void print_config(bit recurse = 0, bit audit = 0); + + // Function -- NODOCS -- print_config_with_audit + // + // Operates the same as print_config except that the audit bit is + // forced to 1. This interface makes user code a bit more readable as + // it avoids multiple arbitrary bit settings in the argument list. + // + // If ~recurse~ is set, then configuration information for all + // children and below are printed as well. + + extern function void print_config_with_audit(bit recurse = 0); + + // Variable: print_config_matches + // + // Setting this static variable causes uvm_config_db::get() to print info about + // matching configuration settings as they are being applied. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + static bit print_config_matches; + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Objection Interface + //---------------------------------------------------------------------------- + // + // These methods provide object level hooks into the + // mechanism. + // + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- raised + // + // The ~raised~ callback is called when this or a descendant of this component + // instance raises the specified ~objection~. The ~source_obj~ is the object + // that originally raised the objection. + // The ~description~ is optionally provided by the ~source_obj~ to give a + // reason for raising the objection. The ~count~ indicates the number of + // objections raised by the ~source_obj~. + + // @uvm-ieee 1800.2-2017 auto 13.1.5.4 + virtual function void raised (uvm_objection objection, uvm_object source_obj, + string description, int count); + endfunction + + + // Function -- NODOCS -- dropped + // + // The ~dropped~ callback is called when this or a descendant of this component + // instance drops the specified ~objection~. The ~source_obj~ is the object + // that originally dropped the objection. + // The ~description~ is optionally provided by the ~source_obj~ to give a + // reason for dropping the objection. The ~count~ indicates the number of + // objections dropped by the ~source_obj~. + + // @uvm-ieee 1800.2-2017 auto 13.1.5.5 + virtual function void dropped (uvm_objection objection, uvm_object source_obj, + string description, int count); + endfunction + + + // Task -- NODOCS -- all_dropped + // + // The ~all_droppped~ callback is called when all objections have been + // dropped by this component and all its descendants. The ~source_obj~ is the + // object that dropped the last objection. + // The ~description~ is optionally provided by the ~source_obj~ to give a + // reason for raising the objection. The ~count~ indicates the number of + // objections dropped by the ~source_obj~. + + // @uvm-ieee 1800.2-2017 auto 13.1.5.6 + virtual task all_dropped (uvm_objection objection, uvm_object source_obj, + string description, int count); + endtask + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Factory Interface + //---------------------------------------------------------------------------- + // + // The factory interface provides convenient access to a portion of UVM's + // interface. For creating new objects and components, the + // preferred method of accessing the factory is via the object or component + // wrapper (see and + // ). The wrapper also provides functions + // for setting type and instance overrides. + // + //---------------------------------------------------------------------------- + + // Function -- NODOCS -- create_component + // + // A convenience function for , + // this method calls upon the factory to create a new child component + // whose type corresponds to the preregistered type name, ~requested_type_name~, + // and instance name, ~name~. This method is equivalent to: + // + //| factory.create_component_by_name(requested_type_name, + //| get_full_name(), name, this); + // + // If the factory determines that a type or instance override exists, the type + // of the component created may be different than the requested type. See + // and . See also for + // details on factory operation. + + extern function uvm_component create_component (string requested_type_name, + string name); + + + // Function -- NODOCS -- create_object + // + // A convenience function for , + // this method calls upon the factory to create a new object + // whose type corresponds to the preregistered type name, + // ~requested_type_name~, and instance name, ~name~. This method is + // equivalent to: + // + //| factory.create_object_by_name(requested_type_name, + //| get_full_name(), name); + // + // If the factory determines that a type or instance override exists, the + // type of the object created may be different than the requested type. See + // for details on factory operation. + + extern function uvm_object create_object (string requested_type_name, + string name=""); + + + // Function -- NODOCS -- set_type_override_by_type + // + // A convenience function for , this + // method registers a factory override for components and objects created at + // this level of hierarchy or below. This method is equivalent to: + // + //| factory.set_type_override_by_type(original_type, override_type,replace); + // + // The ~relative_inst_path~ is relative to this component and may include + // wildcards. The ~original_type~ represents the type that is being overridden. + // In subsequent calls to or + // , if the requested_type matches the + // ~original_type~ and the instance paths match, the factory will produce + // the ~override_type~. + // + // The original and override type arguments are lightweight proxies to the + // types they represent. See for information + // on usage. + + extern static function void set_type_override_by_type + (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + + + // Function -- NODOCS -- set_inst_override_by_type + // + // A convenience function for , this + // method registers a factory override for components and objects created at + // this level of hierarchy or below. In typical usage, this method is + // equivalent to: + // + //| factory.set_inst_override_by_type( original_type, + //| override_type, + //| {get_full_name(),".", + //| relative_inst_path}); + // + // The ~relative_inst_path~ is relative to this component and may include + // wildcards. The ~original_type~ represents the type that is being overridden. + // In subsequent calls to or + // , if the requested_type matches the + // ~original_type~ and the instance paths match, the factory will produce the + // ~override_type~. + // + // The original and override types are lightweight proxies to the types they + // represent. They can be obtained by calling ~type::get_type()~, if + // implemented by ~type~, or by directly calling ~type::type_id::get()~, where + // ~type~ is the user type and ~type_id~ is the name of the typedef to + // or . + // + // If you are employing the `uvm_*_utils macros, the typedef and the get_type + // method will be implemented for you. For details on the utils macros + // refer to . + // + // The following example shows `uvm_*_utils usage: + // + //| class comp extends uvm_component; + //| `uvm_component_utils(comp) + //| ... + //| endclass + //| + //| class mycomp extends uvm_component; + //| `uvm_component_utils(mycomp) + //| ... + //| endclass + //| + //| class block extends uvm_component; + //| `uvm_component_utils(block) + //| comp c_inst; + //| virtual function void build_phase(uvm_phase phase); + //| set_inst_override_by_type("c_inst",comp::get_type(), + //| mycomp::get_type()); + //| endfunction + //| ... + //| endclass + + extern function void set_inst_override_by_type(string relative_inst_path, + uvm_object_wrapper original_type, + uvm_object_wrapper override_type); + + + // Function -- NODOCS -- set_type_override + // + // A convenience function for , + // this method configures the factory to create an object of type + // ~override_type_name~ whenever the factory is asked to produce a type + // represented by ~original_type_name~. This method is equivalent to: + // + //| factory.set_type_override_by_name(original_type_name, + //| override_type_name, replace); + // + // The ~original_type_name~ typically refers to a preregistered type in the + // factory. It may, however, be any arbitrary string. Subsequent calls to + // create_component or create_object with the same string and matching + // instance path will produce the type represented by override_type_name. + // The ~override_type_name~ must refer to a preregistered type in the factory. + + extern static function void set_type_override(string original_type_name, + string override_type_name, + bit replace=1); + + + // Function -- NODOCS -- set_inst_override + // + // A convenience function for , this + // method registers a factory override for components created at this level + // of hierarchy or below. In typical usage, this method is equivalent to: + // + //| factory.set_inst_override_by_name(original_type_name, + //| override_type_name, + //| {get_full_name(),".", + //| relative_inst_path} + //| ); + // + // The ~relative_inst_path~ is relative to this component and may include + // wildcards. The ~original_type_name~ typically refers to a preregistered type + // in the factory. It may, however, be any arbitrary string. Subsequent calls + // to create_component or create_object with the same string and matching + // instance path will produce the type represented by ~override_type_name~. + // The ~override_type_name~ must refer to a preregistered type in the factory. + + extern function void set_inst_override(string relative_inst_path, + string original_type_name, + string override_type_name); + + + // Function -- NODOCS -- print_override_info + // + // This factory debug method performs the same lookup process as create_object + // and create_component, but instead of creating an object, it prints + // information about what type of object would be created given the + // provided arguments. + + extern function void print_override_info(string requested_type_name, + string name=""); + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Hierarchical Reporting Interface + //---------------------------------------------------------------------------- + // + // This interface provides versions of the set_report_* methods in the + // base class that are applied recursively to this + // component and all its children. + // + // When a report is issued and its associated action has the LOG bit set, the + // report will be sent to its associated FILE descriptor. + //---------------------------------------------------------------------------- + + // Function -- NODOCS -- set_report_id_verbosity_hier + + extern function void set_report_id_verbosity_hier (string id, + int verbosity); + + // Function -- NODOCS -- set_report_severity_id_verbosity_hier + // + // These methods recursively associate the specified verbosity with reports of + // the given ~severity~, ~id~, or ~severity-id~ pair. A verbosity associated + // with a particular severity-id pair takes precedence over a verbosity + // associated with id, which takes precedence over a verbosity associated + // with a severity. + // + // For a list of severities and their default verbosities, refer to + // . + + extern function void set_report_severity_id_verbosity_hier(uvm_severity severity, + string id, + int verbosity); + + + // Function -- NODOCS -- set_report_severity_action_hier + + extern function void set_report_severity_action_hier (uvm_severity severity, + uvm_action action); + + + // Function -- NODOCS -- set_report_id_action_hier + + extern function void set_report_id_action_hier (string id, + uvm_action action); + + // Function -- NODOCS -- set_report_severity_id_action_hier + // + // These methods recursively associate the specified action with reports of + // the given ~severity~, ~id~, or ~severity-id~ pair. An action associated + // with a particular severity-id pair takes precedence over an action + // associated with id, which takes precedence over an action associated + // with a severity. + // + // For a list of severities and their default actions, refer to + // . + + extern function void set_report_severity_id_action_hier(uvm_severity severity, + string id, + uvm_action action); + + + + // Function -- NODOCS -- set_report_default_file_hier + + extern function void set_report_default_file_hier (UVM_FILE file); + + // Function -- NODOCS -- set_report_severity_file_hier + + extern function void set_report_severity_file_hier (uvm_severity severity, + UVM_FILE file); + + // Function -- NODOCS -- set_report_id_file_hier + + extern function void set_report_id_file_hier (string id, + UVM_FILE file); + + // Function -- NODOCS -- set_report_severity_id_file_hier + // + // These methods recursively associate the specified FILE descriptor with + // reports of the given ~severity~, ~id~, or ~severity-id~ pair. A FILE + // associated with a particular severity-id pair takes precedence over a FILE + // associated with id, which take precedence over an a FILE associated with a + // severity, which takes precedence over the default FILE descriptor. + // + // For a list of severities and other information related to the report + // mechanism, refer to . + + extern function void set_report_severity_id_file_hier(uvm_severity severity, + string id, + UVM_FILE file); + + + // Function -- NODOCS -- set_report_verbosity_level_hier + // + // This method recursively sets the maximum verbosity level for reports for + // this component and all those below it. Any report from this component + // subtree whose verbosity exceeds this maximum will be ignored. + // + // See for a list of predefined message verbosity levels + // and their meaning. + + extern function void set_report_verbosity_level_hier (int verbosity); + + + // Function -- NODOCS -- pre_abort + // + // This callback is executed when the message system is executing a + // action. The exit action causes an immediate termination of + // the simulation, but the pre_abort callback hook gives components an + // opportunity to provide additional information to the user before + // the termination happens. For example, a test may want to executed + // the report function of a particular component even when an error + // condition has happened to force a premature termination you would + // write a function like: + // + //| function void mycomponent::pre_abort(); + //| report(); + //| endfunction + // + // The pre_abort() callback hooks are called in a bottom-up fashion. + + // @uvm-ieee 1800.2-2017 auto 13.1.4.6 + virtual function void pre_abort; + endfunction + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Recording Interface + //---------------------------------------------------------------------------- + // These methods comprise the component-based transaction recording + // interface. The methods can be used to record the transactions that + // this component "sees", i.e. produces or consumes. + // + // The API and implementation are subject to change once a vendor-independent + // use-model is determined. + //---------------------------------------------------------------------------- + + // Function -- NODOCS -- accept_tr + // + // This function marks the acceptance of a transaction, ~tr~, by this + // component. Specifically, it performs the following actions: + // + // - Calls the ~tr~'s method, passing to it the + // ~accept_time~ argument. + // + // - Calls this component's method to allow for any post-begin + // action in derived classes. + // + // - Triggers the component's internal accept_tr event. Any processes waiting + // on this event will resume in the next delta cycle. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.1 + extern function void accept_tr (uvm_transaction tr, time accept_time = 0); + + + // Function -- NODOCS -- do_accept_tr + // + // The method calls this function to accommodate any user-defined + // post-accept action. Implementations should call super.do_accept_tr to + // ensure correct operation. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.2 + extern virtual protected function void do_accept_tr (uvm_transaction tr); + + + // Function -- NODOCS -- begin_tr + // + // This function marks the start of a transaction, ~tr~, by this component. + // Specifically, it performs the following actions: + // + // - Calls ~tr~'s method, passing to it the + // ~begin_time~ argument. The ~begin_time~ should be greater than or equal + // to the accept time. By default, when ~begin_time~ = 0, the current + // simulation time is used. + // + // If recording is enabled (recording_detail != UVM_OFF), then a new + // database-transaction is started on the component's transaction stream + // given by the stream argument. No transaction properties are recorded at + // this time. + // + // - Calls the component's method to allow for any post-begin + // action in derived classes. + // + // - Triggers the component's internal begin_tr event. Any processes waiting + // on this event will resume in the next delta cycle. + // + // A handle to the transaction is returned. The meaning of this handle, as + // well as the interpretation of the arguments ~stream_name~, ~label~, and + // ~desc~ are vendor specific. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.3 + extern function int begin_tr (uvm_transaction tr, + string stream_name="main", + string label="", + string desc="", + time begin_time=0, + int parent_handle=0); + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- begin_child_tr + // + // This function marks the start of a child transaction, ~tr~, by this + // component. Its operation is identical to that of , except that + // an association is made between this transaction and the provided parent + // transaction. This association is vendor-specific. + // + // This function is deprecated + + extern function int begin_child_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", + string label="", + string desc="", + time begin_time=0); +`endif //UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- do_begin_tr + // + // The and methods call this function to + // accommodate any user-defined post-begin action. Implementations should call + // super.do_begin_tr to ensure correct operation. + + extern virtual protected + // @uvm-ieee 1800.2-2017 auto 13.1.6.4 + function void do_begin_tr (uvm_transaction tr, + string stream_name, + int tr_handle); + + + // Function -- NODOCS -- end_tr + // + // This function marks the end of a transaction, ~tr~, by this component. + // Specifically, it performs the following actions: + // + // - Calls ~tr~'s method, passing to it the + // ~end_time~ argument. The ~end_time~ must at least be greater than the + // begin time. By default, when ~end_time~ = 0, the current simulation time + // is used. + // + // The transaction's properties are recorded to the database-transaction on + // which it was started, and then the transaction is ended. Only those + // properties handled by the transaction's do_record method (and optional + // `uvm_*_field macros) are recorded. + // + // - Calls the component's method to accommodate any post-end + // action in derived classes. + // + // - Triggers the component's internal end_tr event. Any processes waiting on + // this event will resume in the next delta cycle. + // + // The ~free_handle~ bit indicates that this transaction is no longer needed. + // The implementation of free_handle is vendor-specific. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.5 + extern function void end_tr (uvm_transaction tr, + time end_time=0, + bit free_handle=1); + + + // Function -- NODOCS -- do_end_tr + // + // The method calls this function to accommodate any user-defined + // post-end action. Implementations should call super.do_end_tr to ensure + // correct operation. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.6 + extern virtual protected function void do_end_tr (uvm_transaction tr, + int tr_handle); + + + // Function -- NODOCS -- record_error_tr + // + // This function marks an error transaction by a component. Properties of the + // given uvm_object, ~info~, as implemented in its method, + // are recorded to the transaction database. + // + // An ~error_time~ of 0 indicates to use the current simulation time. The + // ~keep_active~ bit determines if the handle should remain active. If 0, + // then a zero-length error transaction is recorded. A handle to the + // database-transaction is returned. + // + // Interpretation of this handle, as well as the strings ~stream_name~, + // ~label~, and ~desc~, are vendor-specific. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.7 + extern function int record_error_tr (string stream_name="main", + uvm_object info=null, + string label="error_tr", + string desc="", + time error_time=0, + bit keep_active=0); + + + // Function -- NODOCS -- record_event_tr + // + // This function marks an event transaction by a component. + // + // An ~event_time~ of 0 indicates to use the current simulation time. + // + // A handle to the transaction is returned. The ~keep_active~ bit determines + // if the handle may be used for other vendor-specific purposes. + // + // The strings for ~stream_name~, ~label~, and ~desc~ are vendor-specific + // identifiers for the transaction. + + // @uvm-ieee 1800.2-2017 auto 13.1.6.8 + extern function int record_event_tr (string stream_name="main", + uvm_object info=null, + string label="event_tr", + string desc="", + time event_time=0, + bit keep_active=0); + + + // @uvm-ieee 1800.2-2017 auto 13.1.6.9 + extern virtual function uvm_tr_stream get_tr_stream(string name, + string stream_type_name=""); + + + // @uvm-ieee 1800.2-2017 auto 13.1.6.10 + extern virtual function void free_tr_stream(uvm_tr_stream stream); + + // Variable -- NODOCS -- print_enabled + // + // This bit determines if this component should automatically be printed as a + // child of its parent object. + // + // By default, all children are printed. However, this bit allows a parent + // component to disable the printing of specific children. + + bit print_enabled = 1; + + // Variable -- NODOCS -- tr_database + // + // Specifies the object to use for + // and other methods in the . + // Default is . + uvm_tr_database tr_database; + + `ifdef UVM_ENABLE_DEPRECATED_API + extern virtual function uvm_tr_database m_get_tr_database(); + `endif // UVM_ENABLE_DEPRECATED_API + + // @uvm-ieee 1800.2-2017 auto 13.1.6.12 + extern virtual function uvm_tr_database get_tr_database(); + + // @uvm-ieee 1800.2-2017 auto 13.1.6.11 + extern virtual function void set_tr_database(uvm_tr_database db); + + + //---------------------------------------------------------------------------- + // PRIVATE or PSUEDO-PRIVATE members + // *** Do not call directly *** + // Implementation and even existence are subject to change. + //---------------------------------------------------------------------------- + // Most local methods are prefixed with m_, indicating they are not + // user-level methods. SystemVerilog does not support friend classes, + // which forces some otherwise internal methods to be exposed (i.e. not + // be protected via 'local' keyword). These methods are also prefixed + // with m_ to indicate they are not intended for public use. + // + // Internal methods will not be documented, although their implementa- + // tions are freely available via the open-source license. + //---------------------------------------------------------------------------- + + protected uvm_domain m_domain; // set_domain stores our domain handle + + /*protected*/ uvm_phase m_phase_imps[uvm_phase]; // functors to override ovm_root defaults + + //TND review protected, provide read-only accessor. + uvm_phase m_current_phase; // the most recently executed phase + protected process m_phase_process; + + /*protected*/ bit m_build_done; + /*protected*/ int m_phasing_active; + +`ifdef UVM_ENABLE_DEPRECATED_API + extern function void set_int_local(string field_name, + uvm_bitstream_t value, + bit recurse=1); +`endif // UVM_ENABLE_DEPRECATED_API + extern function void set_local(uvm_resource_base rsrc) ; + + /*protected*/ uvm_component m_parent; + protected uvm_component m_children[string]; + protected uvm_component m_children_by_handle[uvm_component]; + extern protected virtual function bit m_add_child(uvm_component child); + extern local virtual function void m_set_full_name(); + + extern function void do_resolve_bindings(); + extern function void do_flush(); + + extern virtual function void flush (); + + extern local function void m_extract_name(string name , + output string leaf , + output string remainder ); + + // overridden to disable + extern virtual function uvm_object create (string name=""); + extern virtual function uvm_object clone (); + + local uvm_tr_stream m_streams[string][string]; + local uvm_recorder m_tr_h[uvm_transaction]; + extern protected function int m_begin_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", string label="", + string desc="", time begin_time=0); + + string m_name; + + typedef uvm_abstract_component_registry#(uvm_component, "uvm_component") type_id; + `uvm_type_name_decl("uvm_component") + + protected uvm_event_pool event_pool; + + int unsigned recording_detail = UVM_NONE; + extern function void do_print(uvm_printer printer); + + // Internal methods for setting up command line messaging stuff + extern function void m_set_cl_msg_args; + extern function void m_set_cl_verb; + extern function void m_set_cl_action; + extern function void m_set_cl_sev; + extern function void m_apply_verbosity_settings(uvm_phase phase); + + // The verbosity settings may have a specific phase to start at. + // We will do this work in the phase_started callback. + + typedef struct { + string comp; + string phase; + time offset; + uvm_verbosity verbosity; + string id; + } m_verbosity_setting; + + m_verbosity_setting m_verbosity_settings[$]; + static m_verbosity_setting m_time_settings[$]; + + // does the pre abort callback hierarchically + extern /*local*/ function void m_do_pre_abort; + + // produce message for unsupported types from apply_config_settings + uvm_resource_base m_unsupported_resource_base = null; + extern function void m_unsupported_set_local(uvm_resource_base rsrc); + +typedef struct { + string arg; + string args[$]; + int unsigned used; +} uvm_cmdline_parsed_arg_t; + +static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_action[$]; +static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_sev[$]; + +endclass : uvm_component + +`include "base/uvm_root.svh" + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS- uvm_component +// +//------------------------------------------------------------------------------ + + +// new +// --- + +function uvm_component::new (string name, uvm_component parent); + string error_str; + uvm_root top; + uvm_coreservice_t cs; + + super.new(name); + + // If uvm_top, reset name to "" so it doesn't show in full paths then return + if (parent==null && name == "__top__") begin + set_name(""); // *** VIRTUAL + return; + end + + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + // Check that we're not in or past end_of_elaboration + begin + uvm_phase bld; + uvm_domain common; + common = uvm_domain::get_common_domain(); + bld = common.find(uvm_build_phase::get()); + if (bld == null) + uvm_report_fatal("COMP/INTERNAL", + "attempt to find build phase object failed",UVM_NONE); + if (bld.get_state() == UVM_PHASE_DONE) begin + uvm_report_fatal("ILLCRT", {"It is illegal to create a component ('", + name,"' under '", + (parent == null ? top.get_full_name() : parent.get_full_name()), + "') after the build phase has ended."}, + UVM_NONE); + end + end + + if (name == "") begin + name.itoa(m_inst_count); + name = {"COMP_", name}; + end + + if(parent == this) begin + `uvm_fatal("THISPARENT", "cannot set the parent of a component to itself") + end + + if (parent == null) + parent = top; + + if(uvm_report_enabled(UVM_MEDIUM+1, UVM_INFO, "NEWCOMP")) + `uvm_info("NEWCOMP", {"Creating ", + (parent==top?"uvm_top":parent.get_full_name()),".",name},UVM_MEDIUM+1) + + if (parent.has_child(name) && this != parent.get_child(name)) begin + if (parent == top) begin + error_str = {"Name '",name,"' is not unique to other top-level ", + "instances. If parent is a module, build a unique name by combining the ", + "the module name and component name: $sformatf(\"\%m.\%s\",\"",name,"\")."}; + `uvm_fatal("CLDEXT",error_str) + end + else + `uvm_fatal("CLDEXT", + $sformatf("Cannot set '%s' as a child of '%s', %s", + name, parent.get_full_name(), + "which already has a child by that name.")) + return; + end + + m_parent = parent; + + set_name(name); // *** VIRTUAL + + if (!m_parent.m_add_child(this)) + m_parent = null; + + event_pool = new("event_pool"); + + m_domain = parent.m_domain; // by default, inherit domains from parents + + // Now that inst name is established, reseed (if use_uvm_seeding is set) + reseed(); + + // Do local configuration settings + if (!uvm_config_db #(uvm_bitstream_t)::get(this, "", "recording_detail", recording_detail)) + void'(uvm_config_db #(int)::get(this, "", "recording_detail", recording_detail)); + + m_rh.set_name(get_full_name()); + set_report_verbosity_level(parent.get_report_verbosity_level()); + + m_set_cl_msg_args(); + +endfunction + + +// m_add_child +// ----------- + +function bit uvm_component::m_add_child(uvm_component child); + + if (m_children.exists(child.get_name()) && + m_children[child.get_name()] != child) begin + `uvm_warning("BDCLD", + $sformatf("A child with the name '%0s' (type=%0s) already exists.", + child.get_name(), m_children[child.get_name()].get_type_name())) + return 0; + end + + if (m_children_by_handle.exists(child)) begin + `uvm_warning("BDCHLD", + $sformatf("A child with the name '%0s' %0s %0s'", + child.get_name(), + "already exists in parent under name '", + m_children_by_handle[child].get_name())) + return 0; + end + + m_children[child.get_name()] = child; + m_children_by_handle[child] = child; + return 1; +endfunction + + + +//------------------------------------------------------------------------------ +// +// Hierarchy Methods +// +//------------------------------------------------------------------------------ + + +// get_children +// ------------ + +function void uvm_component::get_children(ref uvm_component children[$]); + foreach(m_children[i]) + children.push_back(m_children[i]); +endfunction + + +// get_first_child +// --------------- + +function int uvm_component::get_first_child(ref string name); + return m_children.first(name); +endfunction + + +// get_next_child +// -------------- + +function int uvm_component::get_next_child(ref string name); + return m_children.next(name); +endfunction + + +// get_child +// --------- + +function uvm_component uvm_component::get_child(string name); + if (m_children.exists(name)) + return m_children[name]; + `uvm_warning("NOCHILD",{"Component with name '",name, + "' is not a child of component '",get_full_name(),"'"}) + return null; +endfunction + + +// has_child +// --------- + +function int uvm_component::has_child(string name); + return m_children.exists(name); +endfunction + + +// get_num_children +// ---------------- + +function int uvm_component::get_num_children(); + return m_children.num(); +endfunction + + +// get_full_name +// ------------- + +function string uvm_component::get_full_name (); + // Note- Implementation choice to construct full name once since the + // full name may be used often for lookups. + if(m_name == "") + return get_name(); + else + return m_name; +endfunction + + +// get_parent +// ---------- + +function uvm_component uvm_component::get_parent (); + return m_parent; +endfunction + + +// set_name +// -------- + +function void uvm_component::set_name (string name); + if(m_name != "") begin + `uvm_error("INVSTNM", $sformatf("It is illegal to change the name of a component. The component name will not be changed to \"%s\"", name)) + return; + end + super.set_name(name); + m_set_full_name(); + +endfunction + + +// m_set_full_name +// --------------- + +function void uvm_component::m_set_full_name(); + uvm_root top; + if ($cast(top, m_parent) || m_parent==null) + m_name = get_name(); + else + m_name = {m_parent.get_full_name(), ".", get_name()}; + + foreach (m_children[c]) begin + uvm_component tmp; + tmp = m_children[c]; + tmp.m_set_full_name(); + end + +endfunction + + +// lookup +// ------ + +function uvm_component uvm_component::lookup( string name ); + + string leaf , remainder; + uvm_component comp; + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + comp = this; + + m_extract_name(name, leaf, remainder); + + if (leaf == "") begin + comp = top; // absolute lookup + m_extract_name(remainder, leaf, remainder); + end + + if (!comp.has_child(leaf)) begin + `uvm_warning("Lookup Error", + $sformatf("Cannot find child %0s",leaf)) + return null; + end + + if( remainder != "" ) + return comp.m_children[leaf].lookup(remainder); + + return comp.m_children[leaf]; + +endfunction + + +// get_depth +// --------- + +function int unsigned uvm_component::get_depth(); + if(m_name == "") return 0; + get_depth = 1; + foreach(m_name[i]) + if(m_name[i] == ".") ++get_depth; +endfunction + + +// m_extract_name +// -------------- + +function void uvm_component::m_extract_name(input string name , + output string leaf , + output string remainder ); + int i , len; + len = name.len(); + + for( i = 0; i < name.len(); i++ ) begin + if( name[i] == "." ) begin + break; + end + end + + if( i == len ) begin + leaf = name; + remainder = ""; + return; + end + + leaf = name.substr( 0 , i - 1 ); + remainder = name.substr( i + 1 , len - 1 ); + + return; +endfunction + + +// flush +// ----- + +function void uvm_component::flush(); + return; +endfunction + + +// do_flush (flush_hier?) +// -------- + +function void uvm_component::do_flush(); + foreach( m_children[s] ) + m_children[s].do_flush(); + flush(); +endfunction + + + +//------------------------------------------------------------------------------ +// +// Factory Methods +// +//------------------------------------------------------------------------------ + + +// create +// ------ + +function uvm_object uvm_component::create (string name =""); + `uvm_error("ILLCRT", + "create cannot be called on a uvm_component. Use create_component instead.") + return null; +endfunction + + +// clone +// ------ + +function uvm_object uvm_component::clone (); + `uvm_error("ILLCLN", $sformatf("Attempting to clone '%s'. Clone cannot be called on a uvm_component. The clone target variable will be set to null.", get_full_name())) + return null; +endfunction + + +// print_override_info +// ------------------- + +function void uvm_component::print_override_info (string requested_type_name, + string name=""); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.debug_create_by_name(requested_type_name, get_full_name(), name); +endfunction + + +// create_component +// ---------------- + +function uvm_component uvm_component::create_component (string requested_type_name, + string name); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + return factory.create_component_by_name(requested_type_name, get_full_name(), + name, this); +endfunction + + +// create_object +// ------------- + +function uvm_object uvm_component::create_object (string requested_type_name, + string name=""); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + return factory.create_object_by_name(requested_type_name, + get_full_name(), name); +endfunction + + +// set_type_override (static) +// ----------------- + +function void uvm_component::set_type_override (string original_type_name, + string override_type_name, + bit replace=1); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.set_type_override_by_name(original_type_name,override_type_name, replace); +endfunction + + +// set_type_override_by_type (static) +// ------------------------- + +function void uvm_component::set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.set_type_override_by_type(original_type, override_type, replace); +endfunction + + +// set_inst_override +// ----------------- + +function void uvm_component::set_inst_override (string relative_inst_path, + string original_type_name, + string override_type_name); + string full_inst_path; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + + if (relative_inst_path == "") + full_inst_path = get_full_name(); + else + full_inst_path = {get_full_name(), ".", relative_inst_path}; + + factory.set_inst_override_by_name( + original_type_name, + override_type_name, + full_inst_path); +endfunction + + +// set_inst_override_by_type +// ------------------------- + +function void uvm_component::set_inst_override_by_type (string relative_inst_path, + uvm_object_wrapper original_type, + uvm_object_wrapper override_type); + string full_inst_path; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + + if (relative_inst_path == "") + full_inst_path = get_full_name(); + else + full_inst_path = {get_full_name(), ".", relative_inst_path}; + + factory.set_inst_override_by_type(original_type, override_type, full_inst_path); + +endfunction + + + +//------------------------------------------------------------------------------ +// +// Hierarchical report configuration interface +// +//------------------------------------------------------------------------------ + +// set_report_id_verbosity_hier +// ------------------------- + +function void uvm_component::set_report_id_verbosity_hier( string id, int verbosity); + set_report_id_verbosity(id, verbosity); + foreach( m_children[c] ) + m_children[c].set_report_id_verbosity_hier(id, verbosity); +endfunction + + +// set_report_severity_id_verbosity_hier +// ---------------------------------- + +function void uvm_component::set_report_severity_id_verbosity_hier( uvm_severity severity, + string id, + int verbosity); + set_report_severity_id_verbosity(severity, id, verbosity); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_verbosity_hier(severity, id, verbosity); +endfunction + + +// set_report_severity_action_hier +// ------------------------- + +function void uvm_component::set_report_severity_action_hier( uvm_severity severity, + uvm_action action); + set_report_severity_action(severity, action); + foreach( m_children[c] ) + m_children[c].set_report_severity_action_hier(severity, action); +endfunction + + +// set_report_id_action_hier +// ------------------------- + +function void uvm_component::set_report_id_action_hier( string id, uvm_action action); + set_report_id_action(id, action); + foreach( m_children[c] ) + m_children[c].set_report_id_action_hier(id, action); +endfunction + + +// set_report_severity_id_action_hier +// ---------------------------------- + +function void uvm_component::set_report_severity_id_action_hier( uvm_severity severity, + string id, + uvm_action action); + set_report_severity_id_action(severity, id, action); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_action_hier(severity, id, action); +endfunction + + +// set_report_severity_file_hier +// ----------------------------- + +function void uvm_component::set_report_severity_file_hier( uvm_severity severity, + UVM_FILE file); + set_report_severity_file(severity, file); + foreach( m_children[c] ) + m_children[c].set_report_severity_file_hier(severity, file); +endfunction + + +// set_report_default_file_hier +// ---------------------------- + +function void uvm_component::set_report_default_file_hier( UVM_FILE file); + set_report_default_file(file); + foreach( m_children[c] ) + m_children[c].set_report_default_file_hier(file); +endfunction + + +// set_report_id_file_hier +// ----------------------- + +function void uvm_component::set_report_id_file_hier( string id, UVM_FILE file); + set_report_id_file(id, file); + foreach( m_children[c] ) + m_children[c].set_report_id_file_hier(id, file); +endfunction + + +// set_report_severity_id_file_hier +// -------------------------------- + +function void uvm_component::set_report_severity_id_file_hier ( uvm_severity severity, + string id, + UVM_FILE file); + set_report_severity_id_file(severity, id, file); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_file_hier(severity, id, file); +endfunction + + +// set_report_verbosity_level_hier +// ------------------------------- + +function void uvm_component::set_report_verbosity_level_hier(int verbosity); + set_report_verbosity_level(verbosity); + foreach( m_children[c] ) + m_children[c].set_report_verbosity_level_hier(verbosity); +endfunction + + + +//------------------------------------------------------------------------------ +// +// Phase interface +// +//------------------------------------------------------------------------------ + + +// phase methods +//-------------- +// these are prototypes for the methods to be implemented in user components +// build_phase() has a default implementation, the others have an empty default + +`ifdef UVM_ENABLE_DEPRECATED_API + `define M_UVM_OVM_PHASE_WARN_AND_CALL(NAME) \ + begin \ + static bit warned; \ + if (!warned) \ + `uvm_warning("UVM/DEPRECATED/COMP/OVM_PHASES", {"The library is calling the deprecated uvm_component::", `"NAME`", " method because UVM_ENABLE_DEPRECATED_API is defined. Usage of this deprecated method by the user may lead to unexpected behavior. Users should use uvm_component::", `"NAME`", "_phase()."}) \ + warned = 1; \ + NAME(); \ + end +`endif // UVM_ENABLE_DEPRECATED_API + +function void uvm_component::build_phase(uvm_phase phase); + m_build_done = 1; +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(build) +`else // !UVM_ENABLE_DEPRECATED_API + if (use_automatic_config()) + apply_config_settings(print_config_matches); +`endif // UVM_ENABLED_DEPRECATED_API +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API +// Backward compatibility build function + +function void uvm_component::build(); + m_build_done = 1; + if (use_automatic_config()) + apply_config_settings(print_config_matches); +endfunction // build +`endif // UVM_ENABLE_DEPRECATED_API + +// these phase methods are common to all components in UVM. For backward +// compatibility, they call the old style name (without the _phse) + +function void uvm_component::connect_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(connect) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endfunction + +function void uvm_component::start_of_simulation_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(start_of_simulation) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endfunction + +function void uvm_component::end_of_elaboration_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(end_of_elaboration) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endfunction + +task uvm_component::run_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(run) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endtask + +function void uvm_component::extract_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(extract) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endfunction + +function void uvm_component::check_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(check) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endfunction + +function void uvm_component::report_phase(uvm_phase phase); +`ifdef UVM_ENABLE_DEPRECATED_API + `M_UVM_OVM_PHASE_WARN_AND_CALL(report) +`endif // UVM_ENABLE_DEPRECATED_API + return; +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + `undef M_UVM_OVM_PHASE_WARN_AND_CALL +`endif + +function void uvm_component::final_phase(uvm_phase phase); return; endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API +// These are the old style phase names. In order for runtime phase names +// to not conflict with user names, the _phase postfix was added. + +function void uvm_component::connect(); return; endfunction +function void uvm_component::start_of_simulation(); return; endfunction +function void uvm_component::end_of_elaboration(); return; endfunction +task uvm_component::run(); return; endtask +function void uvm_component::extract(); return; endfunction +function void uvm_component::check(); return; endfunction +function void uvm_component::report(); return; endfunction +`endif // UVM_ENABLE_DEPRECATED_API + +// these runtime phase methods are only called if a set_domain() is done + +task uvm_component::pre_reset_phase(uvm_phase phase); return; endtask +task uvm_component::reset_phase(uvm_phase phase); return; endtask +task uvm_component::post_reset_phase(uvm_phase phase); return; endtask +task uvm_component::pre_configure_phase(uvm_phase phase); return; endtask +task uvm_component::configure_phase(uvm_phase phase); return; endtask +task uvm_component::post_configure_phase(uvm_phase phase); return; endtask +task uvm_component::pre_main_phase(uvm_phase phase); return; endtask +task uvm_component::main_phase(uvm_phase phase); return; endtask +task uvm_component::post_main_phase(uvm_phase phase); return; endtask +task uvm_component::pre_shutdown_phase(uvm_phase phase); return; endtask +task uvm_component::shutdown_phase(uvm_phase phase); return; endtask +task uvm_component::post_shutdown_phase(uvm_phase phase); return; endtask + + +//------------------------------ +// current phase convenience API +//------------------------------ + + +// phase_started +// ------------- +// phase_started() and phase_ended() are extra callbacks called at the +// beginning and end of each phase, respectively. Since they are +// called for all phases the phase is passed in as an argument so the +// extender can decide what to do, if anything, for each phase. + +function void uvm_component::phase_started(uvm_phase phase); +endfunction + +// phase_ended +// ----------- + +function void uvm_component::phase_ended(uvm_phase phase); +endfunction + + +// phase_ready_to_end +// ------------------ + +function void uvm_component::phase_ready_to_end (uvm_phase phase); +endfunction + +//------------------------------ +// phase / schedule / domain API +//------------------------------ +// methods for VIP creators and integrators to use to set up schedule domains +// - a schedule is a named, organized group of phases for a component base type +// - a domain is a named instance of a schedule in the master phasing schedule + + +// define_domain +// ------------- + +function void uvm_component::define_domain(uvm_domain domain); + uvm_phase schedule; + //schedule = domain.find(uvm_domain::get_uvm_schedule()); + schedule = domain.find_by_name("uvm_sched"); + if (schedule == null) begin + uvm_domain common; + schedule = new("uvm_sched", UVM_PHASE_SCHEDULE); + uvm_domain::add_uvm_phases(schedule); + domain.add(schedule); + common = uvm_domain::get_common_domain(); + if (common.find(domain,0) == null) + common.add(domain,.with_phase(uvm_run_phase::get())); + end + +endfunction + + +// set_domain +// ---------- +// assigns this component [tree] to a domain. adds required schedules into graph +// If called from build, ~hier~ won't recurse into all chilren (which don't exist yet) +// If we have components inherit their parent's domain by default, then ~hier~ +// isn't needed and we need a way to prevent children from inheriting this component's domain + +function void uvm_component::set_domain(uvm_domain domain, int hier=1); + + // build and store the custom domain + m_domain = domain; + define_domain(domain); + if (hier) + foreach (m_children[c]) + m_children[c].set_domain(domain); +endfunction + +// get_domain +// ---------- +// +function uvm_domain uvm_component::get_domain(); + return m_domain; +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API +// set_phase_imp +// ------------- + +function void uvm_component::set_phase_imp(uvm_phase phase, uvm_phase imp, int hier=1); + m_phase_imps[phase] = imp; + if (hier) + foreach (m_children[c]) + m_children[c].set_phase_imp(phase,imp,hier); +endfunction +`endif + +//-------------------------- +// phase runtime control API +//-------------------------- + +// suspend +// ------- + +task uvm_component::suspend(); + `uvm_warning("COMP/SPND/UNIMP", "suspend() not implemented") +endtask + + +// resume +// ------ + +task uvm_component::resume(); + `uvm_warning("COMP/RSUM/UNIMP", "resume() not implemented") +endtask + + +// resolve_bindings +// ---------------- + +function void uvm_component::resolve_bindings(); + return; +endfunction + + +// do_resolve_bindings +// ------------------- + +function void uvm_component::do_resolve_bindings(); + foreach( m_children[s] ) + m_children[s].do_resolve_bindings(); + resolve_bindings(); +endfunction + + + +//------------------------------------------------------------------------------ +// +// Recording interface +// +//------------------------------------------------------------------------------ + +// accept_tr +// --------- + +function void uvm_component::accept_tr (uvm_transaction tr, + time accept_time=0); + uvm_event#(uvm_object) e; + + if(tr == null) + return; + + tr.accept_tr(accept_time); + do_accept_tr(tr); + e = event_pool.get("accept_tr"); + if(e!=null) + e.trigger(); +endfunction + +// begin_tr +// -------- + +function int uvm_component::begin_tr (uvm_transaction tr, + string stream_name="main", + string label="", + string desc="", + time begin_time=0, + int parent_handle=0); + return m_begin_tr(tr, parent_handle, stream_name, label, desc, begin_time); +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API +// begin_child_tr +// -------------- + +function int uvm_component::begin_child_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", + string label="", + string desc="", + time begin_time=0); + static bit have_been_warned; + if(!have_been_warned) begin + uvm_report_warning("UVM/DEPRECATED/COMP/BCT", "The deprecated uvm_component::begin_child_tr method has been called. Attempting to compile without UVM_ENABLE_DEPRECATED_API defined will fail. Use begin_tr instead"); + have_been_warned = 1; + end + + return m_begin_tr(tr, parent_handle, stream_name, label, desc, begin_time); +endfunction +`endif // UVM_ENABLE_DEPRECATED_API + +`ifdef UVM_ENABLE_DEPRECATED_API +// m_get_tr_database +// --------------------- + function uvm_tr_database uvm_component::m_get_tr_database(); + static bit have_been_warned; + if(!have_been_warned) begin + `uvm_warning("UVM/DEPRECATED/COMP/M_GET_TR_DB", "uvm_component::m_get_tr_database() is deprecated, use get_tr_database() in its place") + have_been_warned = 1; + end + return get_tr_database(); + endfunction : m_get_tr_database +`endif // UVM_ENABLE_DEPRECATED_API + +// get_tr_database +// --------------------- + function uvm_tr_database uvm_component::get_tr_database(); + if (tr_database == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + tr_database = cs.get_default_tr_database(); + end + return tr_database; + endfunction : get_tr_database + +// set_tr_database +// --------------------- + function void uvm_component::set_tr_database(uvm_tr_database db); + tr_database = db; + endfunction : set_tr_database + + +// get_tr_stream +// ------------ +function uvm_tr_stream uvm_component::get_tr_stream( string name, + string stream_type_name="" ); + uvm_tr_database db = get_tr_database(); + if (!m_streams.exists(name) || !m_streams[name].exists(stream_type_name)) + m_streams[name][stream_type_name] = db.open_stream(name, this.get_full_name(), stream_type_name); + return m_streams[name][stream_type_name]; +endfunction : get_tr_stream + +// free_tr_stream +// -------------- +function void uvm_component::free_tr_stream(uvm_tr_stream stream); + // Check the null case... + if (stream == null) + return; + + // Then make sure this name/type_name combo exists + if (!m_streams.exists(stream.get_name()) || + !m_streams[stream.get_name()].exists(stream.get_stream_type_name())) + return; + + // Then make sure this name/type_name combo is THIS stream + if (m_streams[stream.get_name()][stream.get_stream_type_name()] != stream) + return; + + // Then delete it from the arrays + m_streams[stream.get_name()].delete(stream.get_type_name()); + if (m_streams[stream.get_name()].size() == 0) + m_streams.delete(stream.get_name()); + + // Finally, free the stream if necessary + if (stream.is_open() || stream.is_closed()) begin + stream.free(); + end +endfunction : free_tr_stream + +// m_begin_tr +// ---------- + +function int uvm_component::m_begin_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", + string label="", + string desc="", + time begin_time=0); + uvm_event#(uvm_object) e; + string name; + string kind; + uvm_tr_database db; + int handle, link_handle; + uvm_tr_stream stream; + uvm_recorder recorder, parent_recorder, link_recorder; + + if (tr == null) + return 0; + + db = get_tr_database(); + + if (parent_handle != 0) + parent_recorder = uvm_recorder::get_recorder_from_handle(parent_handle); + + if (parent_recorder == null) begin + uvm_sequence_item seq; + if ($cast(seq,tr)) begin + uvm_sequence_base parent_seq = seq.get_parent_sequence(); + if (parent_seq != null) begin + parent_recorder = parent_seq.m_tr_recorder; + end + end + end + + if(parent_recorder != null) begin + link_handle = tr.begin_child_tr(begin_time, parent_recorder.get_handle()); + end + else begin + link_handle = tr.begin_tr(begin_time); + end + + if (link_handle != 0) + link_recorder = uvm_recorder::get_recorder_from_handle(link_handle); + + + if (tr.get_name() != "") + name = tr.get_name(); + else + name = tr.get_type_name(); + + if (uvm_verbosity'(recording_detail) != UVM_NONE) begin + if (stream_name == "") + stream_name = "main"; + + stream = get_tr_stream(stream_name, "TVM"); + + if (stream != null ) begin + kind = (parent_recorder == null) ? "Begin_No_Parent, Link" : "Begin_End, Link"; + + recorder = stream.open_recorder(name, begin_time, kind); + + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + + if (parent_recorder != null) begin + tr_database.establish_link(uvm_parent_child_link::get_link(parent_recorder, + recorder)); + end + + if (link_recorder != null) begin + tr_database.establish_link(uvm_related_link::get_link(recorder, + link_recorder)); + end + m_tr_h[tr] = recorder; + end + end + + handle = (recorder == null) ? 0 : recorder.get_handle(); + do_begin_tr(tr, stream_name, handle); + + end + + e = event_pool.get("begin_tr"); + if (e!=null) + e.trigger(tr); + + return handle; + +endfunction -// Status: Partial implementation -// * Hierarchical interface -/* typedef class uvm_objection; -typedef class uvm_sequence_base; -typedef class uvm_sequence_item; */ +// end_tr +// ------ -// @uvm-ieee 1800.2-2017 auto 13.1.1 -//UVM virtual class uvm_component extends uvm_report_object; -virtual class uvm_component extends uvm_object; -//UVM - extern function new (string name, uvm_component parent); // UVM: Test OK (t_uvm_component_hierarchical) - extern virtual function uvm_component get_parent (); // UVM: Test OK (t_uvm_component_hierarchical) - extern virtual function string get_full_name (); // UVM: Test OK (t_uvm_component_hierarchical) - extern local virtual function void m_set_full_name(); - extern function void get_children(ref uvm_component children[$]); // UVM: Test OK (t_uvm_component_hierarchical) - extern function uvm_component get_child (string name); // UVM: Test OK (t_uvm_component_hierarchical) - extern function int get_next_child (ref string name); // UVM: Test OK (t_uvm_component_hierarchical) - extern function int get_first_child (ref string name); // UVM: Test OK (t_uvm_component_hierarchical) - extern function int get_num_children (); // UVM: Test OK (t_uvm_component_hierarchical) - extern function int has_child (string name); // UVM: Test OK (t_uvm_component_hierarchical) - extern virtual function void set_name (string name); - extern function uvm_component lookup (string name); // UVM: Test OK (t_uvm_component_hierarchical) - extern function int unsigned get_depth(); // UVM: Test OK (t_uvm_component_hierarchical) +function void uvm_component::end_tr (uvm_transaction tr, + time end_time=0, + bit free_handle=1); + uvm_event#(uvm_object) e; + uvm_recorder recorder; + if (tr == null) + return; - //---------------------------------------------------------------------------- - // PRIVATE or PSUEDO-PRIVATE members - // *** Do not call directly *** - // Implementation and even existence are subject to change. - //---------------------------------------------------------------------------- - // Most local methods are prefixed with m_, indicating they are not - // user-level methods. SystemVerilog does not support friend classes, - // which forces some otherwise internal methods to be exposed (i.e. not - // be protected via 'local' keyword). These methods are also prefixed - // with m_ to indicate they are not intended for public use. - // - // Internal methods will not be documented, although their implementa- - // tions are freely available via the open-source license. - //---------------------------------------------------------------------------- + tr.end_tr(end_time,free_handle); -`ifdef UVM_ENABLE_DEPRECATED_API - extern function void set_int_local(string field_name, - uvm_bitstream_t value, - bit recurse=1); -`endif // UVM_ENABLE_DEPRECATED_API - //UVM extern function void set_local(uvm_resource_base rsrc) ; + if (uvm_verbosity'(recording_detail) != UVM_NONE) begin - /*protected*/ uvm_component m_parent; - protected uvm_component m_children[string]; - protected uvm_component m_children_by_handle[uvm_component]; - extern protected virtual function bit m_add_child(uvm_component child); - //UVM extern local virtual function void (); + if (m_tr_h.exists(tr)) begin - //UVM extern function void do_resolve_bindings(); - //UVM extern function void do_flush(); + recorder = m_tr_h[tr]; - //UVM extern virtual function void flush (); + do_end_tr(tr, recorder.get_handle()); // callback - extern local function void m_extract_name(string name , - output string leaf , - output string remainder ); + m_tr_h.delete(tr); - // overridden to disable - //UVM extern virtual function uvm_object create (string name=""); - //UVM extern virtual function uvm_object clone (); + tr.record(recorder); - //UVM local uvm_tr_stream m_streams[string][string]; - //UVM local uvm_recorder m_tr_h[uvm_transaction]; - //UVM extern protected function int m_begin_tr (uvm_transaction tr, - //UVM int parent_handle=0, - //UVM string stream_name="main", string label="", - //UVM string desc="", time begin_time=0); + recorder.close(end_time); - string m_name; + if (free_handle) + recorder.free(); + + end + else begin + do_end_tr(tr, 0); // callback + end + + end - //UVM typedef uvm_abstract_component_registry#(uvm_component, "uvm_component") type_id; - //UVM `uvm_type_name_decl("uvm_component") + e = event_pool.get("end_tr"); + if(e!=null) + e.trigger(); - //UVM protected uvm_event_pool event_pool; +endfunction - //UVM int unsigned recording_detail = UVM_NONE; - //UVM extern function void do_print(uvm_printer printer); - // Internal methods for setting up command line messaging stuff - //UVM extern function void m_set_cl_msg_args; - //UVM extern function void m_set_cl_verb; - //UVM extern function void m_set_cl_action; - //UVM extern function void m_set_cl_sev; - //UVM extern function void m_apply_verbosity_settings(uvm_phase phase); +// record_error_tr +// --------------- + +function int uvm_component::record_error_tr (string stream_name="main", + uvm_object info=null, + string label="error_tr", + string desc="", + time error_time=0, + bit keep_active=0); + uvm_recorder recorder; + string etype; + uvm_tr_stream stream; + int handle; + + if(keep_active) etype = "Error, Link"; + else etype = "Error"; + + if(error_time == 0) error_time = $realtime; + + if (stream_name == "") + stream_name = "main"; + + stream = get_tr_stream(stream_name, "TVM"); + + handle = 0; + if (stream != null) begin + + recorder = stream.open_recorder(label, + error_time, + etype); + + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (info!=null) + info.record(recorder); + + recorder.close(error_time); + + if (keep_active == 0) begin + recorder.free(); + end + else begin + handle = recorder.get_handle(); + end + end // if (recorder != null) + end // if (stream != null) + + return handle; +endfunction - // The verbosity settings may have a specific phase to start at. - // We will do this work in the phase_started callback. - typedef struct { - string comp; - string phase; - time offset; - uvm_verbosity verbosity; - string id; - } m_verbosity_setting; +// record_event_tr +// --------------- + +function int uvm_component::record_event_tr (string stream_name="main", + uvm_object info=null, + string label="event_tr", + string desc="", + time event_time=0, + bit keep_active=0); + uvm_recorder recorder; + string etype; + int handle; + uvm_tr_stream stream; + + if(keep_active) etype = "Event, Link"; + else etype = "Event"; + + if(event_time == 0) event_time = $realtime; + + if (stream_name == "") + stream_name = "main"; + + stream = get_tr_stream(stream_name, "TVM"); + + handle = 0; + if (stream != null) begin + recorder = stream.open_recorder(label, + event_time, + etype); + + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (info!=null) + info.record(recorder); + + recorder.close(event_time); + + if (keep_active == 0) begin + recorder.free(); + end + else begin + handle = recorder.get_handle(); + end + end // if (recorder != null) + end // if (stream != null) + + return handle; +endfunction - m_verbosity_setting m_verbosity_settings[$]; - static m_verbosity_setting m_time_settings[$]; +// do_accept_tr +// ------------ - // does the pre abort callback hierarchically - //UVM extern /*local*/ function void m_do_pre_abort; +function void uvm_component::do_accept_tr (uvm_transaction tr); + return; +endfunction - // produce message for unsupported types from apply_config_settings - //UVM uvm_resource_base m_unsupported_resource_base = null; - //UVM extern function void m_unsupported_set_local(uvm_resource_base rsrc); - typedef struct { - string arg; - string args[$]; - int unsigned used; - } uvm_cmdline_parsed_arg_t; +// do_begin_tr +// ----------- + +function void uvm_component::do_begin_tr (uvm_transaction tr, + string stream_name, + int tr_handle); + return; +endfunction + - static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_action[$]; - static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_sev[$]; +// do_end_tr +// --------- + +function void uvm_component::do_end_tr (uvm_transaction tr, + int tr_handle); + return; +endfunction -endclass //------------------------------------------------------------------------------ -// IMPLEMENTATION +// +// Configuration interface +// //------------------------------------------------------------------------------ -// UVM ~ -function uvm_component::new (string name, uvm_component parent); - string error_str; - uvm_root top; - uvm_coreservice_t cs; - super.new(name); +function string uvm_component::massage_scope(string scope); - // If uvm_top, reset name to "" so it doesn't show in full paths then return - if (parent==null && name == "__top__") begin - set_name(""); // *** VIRTUAL - return; - end + // uvm_top + if(scope == "") + return "^$"; - cs = uvm_coreservice_t::get(); - top = cs.get_root(); + if(scope == "*") + return {get_full_name(), ".*"}; - // Check that we're not in or past end_of_elaboration - //UVM begin - //UVM uvm_phase bld; - //UVM uvm_domain common; - //UVM common = uvm_domain::get_common_domain(); - //UVM bld = common.find(uvm_build_phase::get()); - //UVM if (bld == null) - //UVM uvm_report_fatal("COMP/INTERNAL", - //UVM "attempt to find build phase object failed",UVM_NONE); - //UVM if (bld.get_state() == UVM_PHASE_DONE) begin - //UVM uvm_report_fatal("ILLCRT", {"It is illegal to create a component ('", - //UVM name,"' under '", - //UVM (parent == null ? top.get_full_name() : parent.get_full_name()), - //UVM "') after the build phase has ended."}, - //UVM UVM_NONE); - //UVM end - //UVM end + // absolute path to the top-level test + if(scope == "uvm_test_top") + return "uvm_test_top"; - if (name == "") begin - name.itoa(m_inst_count); - name = {"COMP_", name}; - end + // absolute path to uvm_root + if(scope[0] == ".") + return {get_full_name(), scope}; - if(parent == this) begin - `uvm_fatal("THISPARENT", "cannot set the parent of a component to itself") - end + return {get_full_name(), ".", scope}; - if (parent == null) - parent = top; +endfunction - if(uvm_report_enabled(UVM_MEDIUM+1, UVM_INFO, "NEWCOMP")) - `uvm_info("NEWCOMP", {"Creating ", - (parent==top?"uvm_top":parent.get_full_name()),".",name},UVM_MEDIUM+1) - if (parent.has_child(name) && this != parent.get_child(name)) begin - if (parent == top) begin - error_str = {"Name '",name,"' is not unique to other top-level ", - "instances. If parent is a module, build a unique name by combining the ", - "the module name and component name: $sformatf(\"\%m.\%s\",\"",name,"\")."}; - `uvm_fatal("CLDEXT",error_str) - end - else - `uvm_fatal("CLDEXT", - $sformatf("Cannot set '%s' as a child of '%s', %s", - name, parent.get_full_name(), - "which already has a child by that name.")) +`ifdef UVM_ENABLE_DEPRECATED_API +// check_config_usage +// ------------------ + +function void uvm_component::check_config_usage ( bit recurse=1 ); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_queue#(uvm_resource_base) rq; + + rq = rp.find_unused_resources(); + + if(rq.size() == 0) return; - end - m_parent = parent; + uvm_report_info("CFGNRD"," ::: The following resources have at least one write and no reads :::",UVM_INFO); + rp.print_resources(rq, 1); +endfunction +`endif // UVM_ENABLE_DEPRECATED_API - set_name(name); // *** VIRTUAL +// use_automatic_config +// -------------------- +function bit uvm_component::use_automatic_config(); + return 1; +endfunction + +// apply_config_settings +// --------------------- - if (!m_parent.m_add_child(this)) - m_parent = null; +function void uvm_component::apply_config_settings (bit verbose=0); - //UVM event_pool = new("event_pool"); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_queue#(uvm_resource_base) rq; + uvm_resource_base r; - //UVM m_domain = parent.m_domain; // by default, inherit domains from parents + // The following is VERY expensive. Needs refactoring. Should + // get config only for the specific field names in 'field_array'. + // That's because the resource pool is organized first by field name. + // Can further optimize by encoding the value for each 'field_array' + // entry to indicate string, uvm_bitstream_t, or object. That way, + // we call 'get' for specific fields of specific types rather than + // the search-and-cast approach here. + rq = rp.lookup_scope(get_full_name()); + rp.sort_by_precedence(rq); - // Now that inst name is established, reseed (if use_uvm_seeding is set) - //UVM reseed(); + // rq is in precedence order now, so we have to go through in reverse + // order to do the settings. + for(int i=rq.size()-1; i>=0; --i) begin + r = rq.get(i); - // Do local configuration settings - //UVM if (!uvm_config_db #(uvm_bitstream_t)::get(this, "", "recording_detail", recording_detail)) - //UVM void'(uvm_config_db #(int)::get(this, "", "recording_detail", recording_detail)); + if(verbose) + uvm_report_info("CFGAPL",$sformatf("applying configuration to field %s", r.get_name()),UVM_NONE); - //UVM m_rh.set_name(get_full_name()); - //UVM set_report_verbosity_level(parent.get_report_verbosity_level()); + set_local(r); - //UVM m_set_cl_msg_args(); -endfunction + end -function uvm_component uvm_component::get_parent(); - return m_parent; endfunction -// UVM 1:1 -function string uvm_component::get_full_name(); - // Note- Implementation choice to construct full name once since the - // full name may be used often for lookups. - if(m_name == "") - return get_name(); - else - return m_name; -endfunction -// UVM 1:1 -function void uvm_component::get_children(ref uvm_component children[$]); - foreach(m_children[i]) - children.push_back(m_children[i]); -endfunction +// print_config +// ------------ + +function void uvm_component::print_config(bit recurse = 0, audit = 0); + + uvm_resource_pool rp = uvm_resource_pool::get(); + + uvm_report_info("CFGPRT","visible resources:",UVM_INFO); + rp.print_resources(rp.lookup_scope(get_full_name()), audit); + + if(recurse) begin + uvm_component c; + foreach(m_children[name]) begin + c = m_children[name]; + c.print_config(recurse, audit); + end + end -// UVM 1:1 -function uvm_component uvm_component::get_child(string name); - if (m_children.exists(name)) - return m_children[name]; - `uvm_warning("NOCHILD",{"Component with name '",name, - "' is not a child of component '",get_full_name(),"'"}) - return null; endfunction -// UVM 1:1 -function int uvm_component::get_next_child(ref string name); - return m_children.next(name); +`ifdef UVM_ENABLE_DEPRECATED_API +// print_config_settings +// --------------------- + +function void uvm_component::print_config_settings (string field="", + uvm_component comp=null, + bit recurse=0); + static bit have_been_warned; + if(!have_been_warned) begin + uvm_report_warning("UVM/DEPRECATED/COMP/PCS", "The deprecated uvm_component::print_config_settings method has been called. Attempting to compile without UVM_ENABLE_DEPRECATED_API defined will fail. Use uvm_component::print_config() instead."); + have_been_warned = 1; + end + + print_config(recurse, 1); endfunction +`endif // UVM_ENABLE_DEPRECATED_API -// UVM 1:1 -function int uvm_component::get_first_child(ref string name); - return m_children.first(name); +// print_config_with_audit +// ----------------------- + +function void uvm_component::print_config_with_audit(bit recurse = 0); + print_config(recurse, 1); endfunction -// UVM 1:1 -function int uvm_component::get_num_children(); - return m_children.num(); + +// do_print (override) +// -------- + +function void uvm_component::do_print(uvm_printer printer); + super.do_print(printer); + + // It is printed only if its value is other than the default (UVM_NONE) + if(uvm_verbosity'(recording_detail) != UVM_NONE) + case (recording_detail) + UVM_LOW : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_LOW"); + UVM_MEDIUM : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_MEDIUM"); + UVM_HIGH : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_HIGH"); + UVM_FULL : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_FULL"); + default : printer.print_field_int("recording_detail", recording_detail, + $bits(recording_detail), UVM_DEC, , "integral"); + endcase + endfunction -// UVM 1:1 -function int uvm_component::has_child(string name); - return m_children.exists(name); + +`ifdef UVM_ENABLE_DEPRECATED_API +// set_int_local (override) +// ------------- + +function void uvm_component::set_int_local (string field_name, + uvm_bitstream_t value, + bit recurse=1); + + //call the super function to get child recursion and any registered fields + super.set_int_local(field_name, value, recurse); + + //set the local properties + if(uvm_is_match(field_name, "recording_detail")) + recording_detail = value; + endfunction -// UVM 1:1 -function uvm_component uvm_component::lookup( string name ); +`endif // UVM_ENABLE_DEPRECATED_API - string leaf , remainder; - uvm_component comp; - uvm_root top; - uvm_coreservice_t cs; - cs = uvm_coreservice_t::get(); - top = cs.get_root(); - comp = this; +// set_local (override) +// --------- - m_extract_name(name, leaf, remainder); +function void uvm_component::set_local(uvm_resource_base rsrc) ; - if (leaf == "") begin - comp = top; // absolute lookup - m_extract_name(remainder, leaf, remainder); - end + bit success; - if (!comp.has_child(leaf)) begin - `uvm_warning("Lookup Error", - $sformatf("Cannot find child %0s",leaf)) - return null; + //set the local properties + if((rsrc != null) && (rsrc.get_name() == "recording_detail")) begin + `uvm_resource_builtin_int_read(success, + rsrc, + recording_detail, + this) end - if( remainder != "" ) - return comp.m_children[leaf].lookup(remainder); + if (!success) + super.set_local(rsrc); + +endfunction - return comp.m_children[leaf]; +// m_unsupported_set_local (override) +// ---------------------- + +function void uvm_component::m_unsupported_set_local(uvm_resource_base rsrc); + + m_unsupported_resource_base = rsrc; endfunction -// UVM 1:1 -function int unsigned uvm_component::get_depth(); - if(m_name == "") return 0; - get_depth = 1; - foreach(m_name[i]) - if(m_name[i] == ".") ++get_depth; + +// Internal methods for setting messagin parameters from command line switches + +typedef class uvm_cmdline_processor; + + +// m_set_cl_msg_args +// ----------------- + +function void uvm_component::m_set_cl_msg_args; + string s_; + process p_; + + p_=process::self(); + if(p_!=null) + s_=p_.get_randstate(); + else + `uvm_warning("UVM","run_test() invoked from a non process context") + + m_set_cl_verb(); + m_set_cl_action(); + m_set_cl_sev(); + + if(p_!=null) + p_.set_randstate(s_); endfunction -// UVM 1:1 -function void uvm_component::m_extract_name(input string name , - output string leaf , - output string remainder ); - int i , len; - len = name.len(); - for( i = 0; i < name.len(); i++ ) begin - if( name[i] == "." ) begin - break; +// m_set_cl_verb +// ------------- +function void uvm_component::m_set_cl_verb; + // _ALL_ can be used for ids + // +uvm_set_verbosity=,,,, + // +uvm_set_verbosity=uvm_test_top.env0.agent1.*,_ALL_,UVM_FULL,time,800 + + static string values[$]; + static bit first = 1; + string args[$]; + uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); + uvm_root top; + uvm_coreservice_t cs; + + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + if(first) begin + string t[$]; + m_verbosity_setting setting; + void'(clp.get_arg_values("+uvm_set_verbosity=",values)); + foreach(values[i]) begin + args.delete(); + uvm_split_string(values[i], ",", args); + if(((args.size() == 4) || (args.size() == 5)) && (clp.m_convert_verb(args[2], setting.verbosity) == 1) ) + t.push_back(values[i]); + else + uvm_report_warning("UVM/CMDLINE",$sformatf("argument %s not recognized and therefore dropped",values[i])); + end + + values=t; + first=0; + end + + foreach(values[i]) begin + m_verbosity_setting setting; + args.delete(); + uvm_split_string(values[i], ",", args); + + begin + setting.comp = args[0]; + setting.id = args[1]; + void'(clp.m_convert_verb(args[2],setting.verbosity)); + setting.phase = args[3]; + setting.offset = 0; + if(args.size() == 5) setting.offset = args[4].atoi(); + if((setting.phase == "time") && (this == top)) begin + m_time_settings.push_back(setting); + end + + if (uvm_is_match(setting.comp, get_full_name()) ) begin + if((setting.phase == "" || setting.phase == "build" || setting.phase == "time") && + (setting.offset == 0) ) + begin + if(setting.id == "_ALL_") + set_report_verbosity_level(setting.verbosity); + else + set_report_id_verbosity(setting.id, setting.verbosity); + end + else begin + if(setting.phase != "time") begin + m_verbosity_settings.push_back(setting); + end + end + end end end - - if( i == len ) begin - leaf = name; - remainder = ""; - return; + // do time based settings + if(this == top) begin + fork begin + time last_time = 0; + if (m_time_settings.size() > 0) + m_time_settings.sort() with ( item.offset ); + foreach(m_time_settings[i]) begin + uvm_component comps[$]; + top.find_all(m_time_settings[i].comp,comps); + #(m_time_settings[i].offset - last_time); + last_time = m_time_settings[i].offset; + if(m_time_settings[i].id == "_ALL_") begin + foreach(comps[j]) begin + comps[j].set_report_verbosity_level(m_time_settings[i].verbosity); + end + end + else begin + foreach(comps[j]) begin + comps[j].set_report_id_verbosity(m_time_settings[i].id, m_time_settings[i].verbosity); + end + end + end + end join_none // fork begin end +endfunction - leaf = name.substr( 0 , i - 1 ); - remainder = name.substr( i + 1 , len - 1 ); +// m_set_cl_action +// --------------- + +function void uvm_component::m_set_cl_action; + // _ALL_ can be used for ids or severities + // +uvm_set_action=,,, + // +uvm_set_action=uvm_test_top.env0.*,_ALL_,UVM_ERROR,UVM_NO_ACTION + + static bit initialized = 0; + uvm_severity sev; + uvm_action action; + uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst(); + + if(!initialized) begin + string values[$]; + void'(uvm_cmdline_proc.get_arg_values("+uvm_set_action=",values)); + foreach(values[idx]) begin + uvm_cmdline_parsed_arg_t t; + string args[$]; + uvm_split_string(values[idx], ",", args); + + if(args.size() != 4) begin + `uvm_warning("INVLCMDARGS", $sformatf("+uvm_set_action requires 4 arguments, but %0d given for command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args.size(), values[idx])) + continue; + end + if((args[2] != "_ALL_") && !uvm_string_to_severity(args[2], sev)) begin + `uvm_warning("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args[2], values[idx])) + continue; + end + if(!uvm_string_to_action(args[3], action)) begin + `uvm_warning("INVLCMDARGS", $sformatf("Bad action argument \"%s\" given to command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args[3], values[idx])) + continue; + end + t.args=args; + t.arg=values[idx]; + m_uvm_applied_cl_action.push_back(t); + end + initialized=1; + end + + foreach(m_uvm_applied_cl_action[i]) begin + string args[$] = m_uvm_applied_cl_action[i].args; + + if (!uvm_is_match(args[0], get_full_name()) ) continue; + + void'(uvm_string_to_severity(args[2], sev)); + void'(uvm_string_to_action(args[3], action)); + + m_uvm_applied_cl_action[i].used++; + if(args[1] == "_ALL_") begin + if(args[2] == "_ALL_") begin + set_report_severity_action(UVM_INFO, action); + set_report_severity_action(UVM_WARNING, action); + set_report_severity_action(UVM_ERROR, action); + set_report_severity_action(UVM_FATAL, action); + end + else begin + set_report_severity_action(sev, action); + end + end + else begin + if(args[2] == "_ALL_") begin + set_report_id_action(args[1], action); + end + else begin + set_report_severity_id_action(sev, args[1], action); + end + end + end - return; endfunction -// UVM 1:1 -function bit uvm_component::m_add_child(uvm_component child); - if (m_children.exists(child.get_name()) && - m_children[child.get_name()] != child) begin - `uvm_warning("BDCLD", - $sformatf("A child with the name '%0s' (type=%0s) already exists.", - child.get_name(), m_children[child.get_name()].get_type_name())) - return 0; +// m_set_cl_sev +// ------------ + +function void uvm_component::m_set_cl_sev; + // _ALL_ can be used for ids or severities + // +uvm_set_severity=,,, + // +uvm_set_severity=uvm_test_top.env0.*,BAD_CRC,UVM_ERROR,UVM_WARNING + + static bit initialized; + uvm_severity orig_sev, sev; + uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst(); + + if(!initialized) begin + string values[$]; + void'(uvm_cmdline_proc.get_arg_values("+uvm_set_severity=",values)); + foreach(values[idx]) begin + uvm_cmdline_parsed_arg_t t; + string args[$]; + uvm_split_string(values[idx], ",", args); + if(args.size() != 4) begin + `uvm_warning("INVLCMDARGS", $sformatf("+uvm_set_severity requires 4 arguments, but %0d given for command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args.size(), values[idx])) + continue; + end + if(args[2] != "_ALL_" && !uvm_string_to_severity(args[2], orig_sev)) begin + `uvm_warning("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args[2], values[idx])) + continue; + end + if(!uvm_string_to_severity(args[3], sev)) begin + `uvm_warning("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args[3], values[idx])) + continue; + end + + t.args=args; + t.arg=values[idx]; + m_uvm_applied_cl_sev.push_back(t); + end + initialized=1; end - if (m_children_by_handle.exists(child)) begin - `uvm_warning("BDCHLD", - $sformatf("A child with the name '%0s' %0s %0s'", - child.get_name(), - "already exists in parent under name '", - m_children_by_handle[child].get_name())) - return 0; + foreach(m_uvm_applied_cl_sev[i]) begin + string args[$]=m_uvm_applied_cl_sev[i].args; + + if (!uvm_is_match(args[0], get_full_name()) ) continue; + + void'(uvm_string_to_severity(args[2], orig_sev)); + void'(uvm_string_to_severity(args[3], sev)); + m_uvm_applied_cl_sev[i].used++; + if(args[1] == "_ALL_" && args[2] == "_ALL_") begin + set_report_severity_override(UVM_INFO,sev); + set_report_severity_override(UVM_WARNING,sev); + set_report_severity_override(UVM_ERROR,sev); + set_report_severity_override(UVM_FATAL,sev); end - - m_children[child.get_name()] = child; - m_children_by_handle[child] = child; - return 1; + else if(args[1] == "_ALL_") begin + set_report_severity_override(orig_sev,sev); + end + else if(args[2] == "_ALL_") begin + set_report_severity_id_override(UVM_INFO,args[1],sev); + set_report_severity_id_override(UVM_WARNING,args[1],sev); + set_report_severity_id_override(UVM_ERROR,args[1],sev); + set_report_severity_id_override(UVM_FATAL,args[1],sev); + end + else begin + set_report_severity_id_override(orig_sev,args[1],sev); + end + end endfunction -// UVM 1:1 -function void uvm_component::set_name (string name); - if(m_name != "") begin - `uvm_error("INVSTNM", $sformatf("It is illegal to change the name of a component. The component name will not be changed to \"%s\"", name)) - return; - end - super.set_name(name); - m_set_full_name(); +// m_apply_verbosity_settings +// -------------------------- + +function void uvm_component::m_apply_verbosity_settings(uvm_phase phase); + int i; + while (i < m_verbosity_settings.size()) begin + if(phase.get_name() == m_verbosity_settings[i].phase) begin + if( m_verbosity_settings[i].offset == 0 ) begin + if(m_verbosity_settings[i].id == "_ALL_") + set_report_verbosity_level(m_verbosity_settings[i].verbosity); + else + set_report_id_verbosity(m_verbosity_settings[i].id, m_verbosity_settings[i].verbosity); + end + else begin + process p = process::self(); + string p_rand = p.get_randstate(); + fork begin + m_verbosity_setting setting = m_verbosity_settings[i]; +`ifdef VERILATOR // https://github.com/verilator/verilator/issues/2410 + #(setting.offset); +`else // Functionally equivelent original code, included here for comparison + #setting.offset; +`endif + if(setting.id == "_ALL_") + set_report_verbosity_level(setting.verbosity); + else + set_report_id_verbosity(setting.id, setting.verbosity); + end join_none + p.set_randstate(p_rand); + end + // Remove after use + m_verbosity_settings.delete(i); + continue; + end // if (phase.get_name() == m_verbosity_settings[i].phase) + i++; + end // while (i < m_verbosity_settings.size()) endfunction -// UVM 1:1 -function void uvm_component::m_set_full_name(); - uvm_root top; - if ($cast(top, m_parent) || m_parent==null) - m_name = get_name(); - else - m_name = {m_parent.get_full_name(), ".", get_name()}; - foreach (m_children[c]) begin - uvm_component tmp; - tmp = m_children[c]; - tmp.m_set_full_name(); - end +// m_do_pre_abort +// -------------- +function void uvm_component::m_do_pre_abort; + foreach(m_children[i]) + m_children[i].m_do_pre_abort(); + pre_abort(); endfunction - -//----- diff --git a/test_regress/t/t_uvm/base/uvm_config_db.svh b/test_regress/t/t_uvm/base/uvm_config_db.svh new file mode 100644 index 0000000000..97c5a1c0fb --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_config_db.svh @@ -0,0 +1,406 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2014 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2011-2012 AMD +// Copyright 2012-2018 NVIDIA Corporation +// Copyright 2014-2017 Cisco Systems, Inc. +// Copyright 2011 Cypress Semiconductor Corp. +// Copyright 2017 Verific +// 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. +//---------------------------------------------------------------------- + +typedef class uvm_phase; + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM Configuration Database +// +// Topic: Intro +// +// The class provides a convenience interface +// on top of the to simplify the basic interface +// that is used for configuring instances. +// +// If the run-time ~+UVM_CONFIG_DB_TRACE~ command line option is specified, +// all configuration DB accesses (read and write) are displayed. +//---------------------------------------------------------------------- + +//Internal class for config waiters +class m_uvm_waiter; + string inst_name; + string field_name; + event trigger; + function new (string inst_name, string field_name); + this.inst_name = inst_name; + this.field_name = field_name; + endfunction +endclass + +typedef class uvm_root; +typedef class uvm_config_db_options; + + +// @uvm-ieee 1800.2-2017 auto C.4.2.1 +class uvm_config_db#(type T=int) extends uvm_resource_db#(T); + + // Internal lookup of config settings so they can be reused + // The context has a pool that is keyed by the inst/field name. + static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component]; + + // Internal waiter list for wait_modified + static local uvm_queue#(m_uvm_waiter) m_waiters[string]; + + // function -- NODOCS -- get + // + // Get the value for ~field_name~ in ~inst_name~, using component ~cntxt~ as + // the starting search point. ~inst_name~ is an explicit instance name + // relative to ~cntxt~ and may be an empty string if the ~cntxt~ is the + // instance that the configuration object applies to. ~field_name~ + // is the specific field in the scope that is being searched for. + // + // The basic ~get_config_*~ methods from are mapped to + // this function as: + // + //| get_config_int(...) => uvm_config_db#(uvm_bitstream_t)::get(cntxt,...) + //| get_config_string(...) => uvm_config_db#(string)::get(cntxt,...) + //| get_config_object(...) => uvm_config_db#(uvm_object)::get(cntxt,...) + + // @uvm-ieee 1800.2-2017 auto C.4.2.2.2 + static function bit get(uvm_component cntxt, + string inst_name, + string field_name, + inout T value); +//TBD: add file/line + uvm_resource#(T) r; + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_types::rsrc_q_t rq; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + + if(cntxt == null) + cntxt = cs.get_root(); + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + + rq = rp.lookup_regex_names(inst_name, field_name, uvm_resource#(T)::get_type()); + r = uvm_resource#(T)::get_highest_precedence(rq); + + if(uvm_config_db_options::is_tracing()) + m_show_msg("CFGDB/GET", "Configuration","read", inst_name, field_name, cntxt, r); + + if(r == null) + return 0; + + value = r.read(cntxt); + + return 1; + endfunction + + // function -- NODOCS -- set + // + // Create a new or update an existing configuration setting for + // ~field_name~ in ~inst_name~ from ~cntxt~. + // The setting is made at ~cntxt~, with the full scope of the set + // being {~cntxt~,".",~inst_name~}. If ~cntxt~ is ~null~ then ~inst_name~ + // provides the complete scope information of the setting. + // ~field_name~ is the target field. Both ~inst_name~ and ~field_name~ + // may be glob style or regular expression style expressions. + // + // If a setting is made at build time, the ~cntxt~ hierarchy is + // used to determine the setting's precedence in the database. + // Settings from hierarchically higher levels have higher + // precedence. Settings from the same level of hierarchy have + // a last setting wins semantic. A precedence setting of + // is used for uvm_top, and + // each hierarchical level below the top is decremented by 1. + // + // After build time, all settings use the default precedence and thus + // have a last wins semantic. So, if at run time, a low level + // component makes a runtime setting of some field, that setting + // will have precedence over a setting from the test level that was + // made earlier in the simulation. + // + // The basic ~set_config_*~ methods from are mapped to + // this function as: + // + //| set_config_int(...) => uvm_config_db#(uvm_bitstream_t)::set(cntxt,...) + //| set_config_string(...) => uvm_config_db#(string)::set(cntxt,...) + //| set_config_object(...) => uvm_config_db#(uvm_object)::set(cntxt,...) + + // @uvm-ieee 1800.2-2017 auto C.4.2.2.1 + static function void set(uvm_component cntxt, + string inst_name, + string field_name, + T value); + + uvm_root top; + uvm_phase curr_phase; + uvm_resource#(T) r; + bit exists; + string lookup; + uvm_pool#(string,uvm_resource#(T)) pool; + string rstate; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_resource_pool rp = cs.get_resource_pool(); + int unsigned precedence; + + //take care of random stability during allocation + process p = process::self(); + if(p != null) + rstate = p.get_randstate(); + + top = cs.get_root(); + + curr_phase = top.m_current_phase; + + if(cntxt == null) + cntxt = top; + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + + if(!m_rsc.exists(cntxt)) begin + m_rsc[cntxt] = new; + end + pool = m_rsc[cntxt]; + + // Insert the token in the middle to prevent cache + // oddities like i=foobar,f=xyz and i=foo,f=barxyz. + // Can't just use '.', because '.' isn't illegal + // in field names + lookup = {inst_name, "__M_UVM__", field_name}; + + if(!pool.exists(lookup)) begin + r = new(field_name); + rp.set_scope(r, inst_name); + pool.add(lookup, r); + end + else begin + r = pool.get(lookup); + exists = 1; + end + + if(curr_phase != null && curr_phase.get_name() == "build") + precedence = cs.get_resource_pool_default_precedence() - (cntxt.get_depth()); + else + precedence = cs.get_resource_pool_default_precedence(); + + rp.set_precedence(r, precedence); + r.write(value, cntxt); + + rp.set_priority_name(r, uvm_resource_types::PRI_HIGH); + + //trigger any waiters + if(m_waiters.exists(field_name)) begin + m_uvm_waiter w; + for(int i=0; iw.trigger; + end + end + + if(p != null) + p.set_randstate(rstate); + + if(uvm_config_db_options::is_tracing()) + m_show_msg("CFGDB/SET", "Configuration","set", inst_name, field_name, cntxt, r); + endfunction + + + // function -- NODOCS -- exists + // + // Check if a value for ~field_name~ is available in ~inst_name~, using + // component ~cntxt~ as the starting search point. ~inst_name~ is an explicit + // instance name relative to ~cntxt~ and may be an empty string if the + // ~cntxt~ is the instance that the configuration object applies to. + // ~field_name~ is the specific field in the scope that is being searched for. + // The ~spell_chk~ arg can be set to 1 to turn spell checking on if it + // is expected that the field should exist in the database. The function + // returns 1 if a config parameter exists and 0 if it doesn't exist. + // + + // @uvm-ieee 1800.2-2017 auto C.4.2.2.3 + static function bit exists(uvm_component cntxt, string inst_name, + string field_name, bit spell_chk=0); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + + if(cntxt == null) + cntxt = cs.get_root(); + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + + return (uvm_resource_db#(T)::get_by_name(inst_name,field_name,spell_chk) != null); + endfunction + + + // Function -- NODOCS -- wait_modified + // + // Wait for a configuration setting to be set for ~field_name~ + // in ~cntxt~ and ~inst_name~. The task blocks until a new configuration + // setting is applied that effects the specified field. + + // @uvm-ieee 1800.2-2017 auto C.4.2.2.4 + static task wait_modified(uvm_component cntxt, string inst_name, + string field_name); + process p = process::self(); + string rstate = p.get_randstate(); + m_uvm_waiter waiter; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + + if(cntxt == null) + cntxt = cs.get_root(); + if(cntxt != cs.get_root()) begin + if(inst_name != "") + inst_name = {cntxt.get_full_name(),".",inst_name}; + else + inst_name = cntxt.get_full_name(); + end + + waiter = new(inst_name, field_name); + + if(!m_waiters.exists(field_name)) + m_waiters[field_name] = new; + m_waiters[field_name].push_back(waiter); + + p.set_randstate(rstate); + + // wait on the waiter to trigger + @waiter.trigger; + + // Remove the waiter from the waiter list + for(int i=0; i +// and methods are passed a uvm_copier policy +// object. +// +//------------------------------------------------------------------------------ + +// Class: uvm_copier +// Implementation of the uvm_copier class, as defined in section +// 16.6.1 of 1800.2-2017 + +// @uvm-ieee 1800.2-2017 auto 16.6.1 +class uvm_copier extends uvm_policy; + // @uvm-ieee 1800.2-2017 auto 16.6.2.2 + `uvm_object_utils(uvm_copier) + // Variable -- NODOCS -- policy + // + // Determines whether comparison is UVM_DEEP, UVM_REFERENCE, or UVM_SHALLOW. + + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + + + // @uvm-ieee 1800.2-2017 auto 16.6.2.1 + function new(string name="uvm_copier") ; + super.new(name); + endfunction + + // Implementation only. + + // Implementation only. Not present in the LRM. + //recursion_state_e m_saved_state[uvm_object /*LHS*/][uvm_object /*RHS*/][uvm_recursion_policy_enum /*recursion*/]; + + recursion_state_e m_recur_states[uvm_object /*RHS*/][uvm_object /*LHS*/][uvm_recursion_policy_enum /*recursion*/]; + + // Function -- copy_object + // + // Copies two class objects using the knob to determine whether the + // comparison should be deep, shallow, or reference. + // + // The name input is used for purposes of storing and printing a miscompare. + // + // The ~lhs~ and ~rhs~ objects are the two objects used for comparison. + // + // The ~check_type~ determines whether or not to verify the object + // types match (the return from ~lhs.get_type_name()~ matches + // ~rhs.get_type_name()~). + + // @uvm-ieee 1800.2-2017 auto 16.6.4.1 + virtual function void copy_object ( + uvm_object lhs, + uvm_object rhs); + + uvm_field_op field_op; + if (get_recursion_policy() == UVM_REFERENCE) begin + `uvm_error("UVM_COPY_POLICY","Attempting to make a copy of a object which is a reference") + return; + end + + if (rhs == null || lhs == null) begin + `uvm_error("UVM_COPY_NULL_OBJ","Attempting to make a copy of a object with null src/target") + return; + end + + push_active_object(lhs); + m_recur_states[rhs][lhs][get_recursion_policy()] = uvm_policy::STARTED; + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_COPY,this,rhs); + lhs.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + lhs.do_copy(rhs); + end + field_op.m_recycle(); + m_recur_states[rhs][lhs][get_recursion_policy()] = uvm_policy::FINISHED; + void'(pop_active_object()); + endfunction + + // @uvm-ieee 1800.2-2017 auto 16.6.4.2 + virtual function recursion_state_e object_copied( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion + ); + if (!m_recur_states.exists(rhs)) return NEVER ; + else if (!m_recur_states[rhs].exists(lhs)) return NEVER ; + else if (!m_recur_states[rhs][lhs].exists(recursion)) return NEVER ; + else begin + return m_recur_states[rhs][lhs][recursion]; + end + + + +endfunction + + +function void flush(); + m_recur_states.delete(); +endfunction + +// @uvm-ieee 1800.2-2017 auto 16.6.3 +virtual function void set_recursion_policy (uvm_recursion_policy_enum policy); + this.policy = policy; +endfunction + +// @uvm-ieee 1800.2-2017 auto 16.6.3 +virtual function uvm_recursion_policy_enum get_recursion_policy(); + return policy; +endfunction + +// Function: get_num_copies +// +// Returns the number of times the ~rhs~ has been copied to a unique ~lhs~ +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +function int unsigned get_num_copies(uvm_object rhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].size(); + return 0; +endfunction : get_num_copies + +// Function: get_first_copy +// +//| function int get_first_copy(uvm_object rhs, ref uvm_object lhs) +// +// assigns to the ~lhs~ the value of the first (smallest) object that +// was copied from the ~rhs~. It returns 0 if the ~rhs~ hasn't been copied; +// otherwise, it returns 1. +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +`uvm_copier_get_function(first) + + +// Function: get_next_copy +// +//| function int get_next_copy(uvm_object rhs, ref uvm_object lhs) +// +// finds the smallest object that was copied from the ~rhs~ whose value is +// greater than the given ~lhs~ object argument. If there is a next entry, +// the ~lhs~ is assigned the value of the next object, and the function returns 1. +// Otherwise, the ~lhs~ is unchanged, and the function returns 0. +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +`uvm_copier_get_function(next) + +// Function: get_last_copy +// +//| function int get_last_copy(uvm_object rhs, ref uvm_object lhs) +// +// assigns to the ~lhs~ the value of the last (largest) object that +// was copied from the ~rhs~. It returns 0 if the ~rhs~ hasn't been copied; +// otherwise, it returns 1. +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +`uvm_copier_get_function(last) + +// Function: get_prev_copy +// +//| function int get_prev_copy(uvm_object rhs, ref uvm_object lhs) +// +// finds the largest object that was copied from the ~rhs~ whose value is +// smaller than the given ~lhs~ object argument. If there is a previous entry, +// the ~lhs~ is assigned the value of the previous object, and the function returns 1. +// Otherwise, the ~lhs~ is unchanged, and the function returns 0. +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +`uvm_copier_get_function(prev) + +// @uvm-ieee 1800.2-2017 auto 16.6.2.3 +static function void set_default (uvm_copier copier) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_copier(copier) ; +endfunction + +// @uvm-ieee 1800.2-2017 auto 16.6.2.4 +static function uvm_copier get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_copier() ; +endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_coreservice.svh b/test_regress/t/t_uvm/base/uvm_coreservice.svh index 774d978910..477b6723a9 100644 --- a/test_regress/t/t_uvm/base/uvm_coreservice.svh +++ b/test_regress/t/t_uvm/base/uvm_coreservice.svh @@ -1,14 +1,12 @@ -// SPDX-License-Identifier: Apache-2.0 -// -//------------------------------------------------------------------------------ -// Copyright 2007-2011 Mentor Graphics Corporation +//---------------------------------------------------------------------- +// Copyright 2014-2018 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. // Copyright 2014 Semifore -// Copyright 2010-2018 Synopsys, Inc. -// Copyright 2007-2018 Cadence Design Systems, Inc. -// Copyright 2010-2012 AMD -// Copyright 2012-2018 NVIDIA Corporation -// Copyright 2012-2018 Cisco Systems, Inc. -// Copyright 2012 Accellera Systems Initiative +// Copyright 2018 Intel Corporation +// Copyright 2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014-2017 Cisco Systems, Inc. // Copyright 2017 Verific // All Rights Reserved Worldwide // @@ -25,37 +23,421 @@ // CONDITIONS OF ANY KIND, either express or implied. See // the License for the specific language governing // permissions and limitations under the License. -//------------------------------------------------------------------------------ +//---------------------------------------------------------------------- +typedef class uvm_factory; +typedef class uvm_default_factory; +typedef class uvm_report_server; +typedef class uvm_default_report_server; +typedef class uvm_root; +typedef class uvm_visitor; +typedef class uvm_component_name_check_visitor; +typedef class uvm_component; +typedef class uvm_comparer; +typedef class uvm_copier; +typedef class uvm_packer; +typedef class uvm_printer; +typedef class uvm_table_printer; -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- +typedef class uvm_tr_database; +typedef class uvm_text_tr_database; +typedef class uvm_resource_pool; +`ifdef UVM_ENABLE_DEPRECATED_API +typedef class uvm_object; +`endif -// Status: MOCK -//UVM virtual class uvm_coreservice_t; -class uvm_coreservice_t; -//UVM - `ifdef VERILATOR - static uvm_coreservice_t inst; -`else +typedef class uvm_default_coreservice_t; + +// Title: Core Service + + +// +// Class: uvm_coreservice_t +// +// The library implements the following public API in addition to what +// is documented in IEEE 1800.2. +// + +// @uvm-ieee 1800.2-2017 auto F.4.1.1 +virtual class uvm_coreservice_t; + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.2 + pure virtual function uvm_factory get_factory(); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.3 + pure virtual function void set_factory(uvm_factory f); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.4 + pure virtual function uvm_report_server get_report_server(); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.5 + pure virtual function void set_report_server(uvm_report_server server); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.6 + pure virtual function uvm_tr_database get_default_tr_database(); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.7 + pure virtual function void set_default_tr_database(uvm_tr_database db); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.9 + pure virtual function void set_component_visitor(uvm_visitor#(uvm_component) v); + + pure virtual function uvm_visitor#(uvm_component) get_component_visitor(); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.1 + pure virtual function uvm_root get_root(); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.10 + pure virtual function void set_phase_max_ready_to_end(int max); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.11 + pure virtual function int get_phase_max_ready_to_end(); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.12 + pure virtual function void set_default_printer(uvm_printer printer); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.13 + pure virtual function uvm_printer get_default_printer(); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.14 + pure virtual function void set_default_packer(uvm_packer packer); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.15 + pure virtual function uvm_packer get_default_packer(); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.16 + pure virtual function void set_default_comparer(uvm_comparer comparer); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.17 + pure virtual function uvm_comparer get_default_comparer(); + + pure virtual function int unsigned get_global_seed(); + + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.18 + pure virtual function void set_default_copier(uvm_copier copier); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.19 + pure virtual function uvm_copier get_default_copier(); + + + + // Function: get_uvm_seeding + // Returns the current UVM seeding ~enable~ value, as set by + // . + // + // This pure virtual method provides access to the + // method as described + // by F.4.3. + // + // It was omitted from the P1800.2 LRM, and is being tracked + // in Mantis 6417 + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + pure virtual function bit get_uvm_seeding(); + + // Function: set_uvm_seeding + // Sets the current UVM seeding ~enable~ value, as retrieved by + // . + // + // This pure virtual method provides access to the + // method as described + // by F.4.4. + // + // It was omitted from the P1800.2 LRM, and is being tracked + // in Mantis 6417 + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + pure virtual function void set_uvm_seeding(bit enable); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.21 + pure virtual function void set_resource_pool (uvm_resource_pool pool); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.22 + pure virtual function uvm_resource_pool get_resource_pool(); + + // @uvm-ieee 1800.2-2017 auto F.4.1.4.23 + pure virtual function void set_resource_pool_default_precedence(int unsigned precedence); + + pure virtual function int unsigned get_resource_pool_default_precedence(); + local static uvm_coreservice_t inst; + + // @uvm-ieee 1800.2-2017 auto F.4.1.3 + static function uvm_coreservice_t get(); + if(inst==null) + uvm_init(null); + + return inst; + endfunction // get + + static function void set(uvm_coreservice_t cs); + inst=cs; + endfunction +endclass + +// Class: uvm_default_coreservice_t +// Implementation of the uvm_default_coreservice_t as defined in +// section F.4.2.1 of 1800.2-2017. +// +//| class uvm_default_coreservice_t extends uvm_coreservice_t +// + +// @uvm-ieee 1800.2-2017 auto F.4.2.1 +class uvm_default_coreservice_t extends uvm_coreservice_t; + local uvm_factory factory; + + // Function --NODOCS-- get_factory + // + // Returns the currently enabled uvm factory. + // When no factory has been set before, instantiates a uvm_default_factory + virtual function uvm_factory get_factory(); + if(factory==null) begin + uvm_default_factory f; + f=new; + factory=f; + end + + return factory; + endfunction + + // Function --NODOCS-- set_factory + // + // Sets the current uvm factory. + // Please note: it is up to the user to preserve the contents of the original factory or delegate calls to the original factory + virtual function void set_factory(uvm_factory f); + factory = f; + endfunction + + local uvm_tr_database tr_database; + // Function --NODOCS-- get_default_tr_database + // returns the current default record database + // + // If no default record database has been set before this method + // is called, returns an instance of + virtual function uvm_tr_database get_default_tr_database(); + if (tr_database == null) begin + process p = process::self(); + uvm_text_tr_database tx_db; + string s; + if(p != null) + s = p.get_randstate(); + + tx_db = new("default_tr_database"); + tr_database = tx_db; + + if(p != null) + p.set_randstate(s); + end + return tr_database; + endfunction : get_default_tr_database + + // Function --NODOCS-- set_default_tr_database + // Sets the current default record database to ~db~ + virtual function void set_default_tr_database(uvm_tr_database db); + tr_database = db; + endfunction : set_default_tr_database + + local uvm_report_server report_server; + // Function --NODOCS-- get_report_server + // returns the current global report_server + // if no report server has been set before, returns an instance of + // uvm_default_report_server + virtual function uvm_report_server get_report_server(); + if(report_server==null) begin + uvm_default_report_server f; + f=new; + report_server=f; + end + + return report_server; + endfunction + + // Function --NODOCS-- set_report_server + // sets the central report server to ~server~ + virtual function void set_report_server(uvm_report_server server); + report_server=server; + endfunction + + virtual function uvm_root get_root(); + return uvm_root::m_uvm_get_root(); + endfunction + + local uvm_visitor#(uvm_component) _visitor; + // Function --NODOCS-- set_component_visitor + // sets the component visitor to ~v~ + // (this visitor is being used for the traversal at end_of_elaboration_phase + // for instance for name checking) + virtual function void set_component_visitor(uvm_visitor#(uvm_component) v); + _visitor=v; + endfunction + + // Function --NODOCS-- get_component_visitor + // retrieves the current component visitor + // if unset(or ~null~) returns a instance + virtual function uvm_visitor#(uvm_component) get_component_visitor(); + if(_visitor==null) begin + uvm_component_name_check_visitor v = new("name-check-visitor"); + _visitor=v; + end + return _visitor; + endfunction + + local uvm_printer m_printer ; + + virtual function void set_default_printer(uvm_printer printer); +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_default_printer = printer ; +`else + m_printer = printer ; +`endif + endfunction + + // Function: get_default_printer + // Implementation of the get_default_printer method, as defined in + // section F.4.1.4.13 of 1800.2-2017. + // + // The default printer type returned by this function is + // a uvm_table_printer, unless the default printer has been set to + // another printer type + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + virtual function uvm_printer get_default_printer(); +`ifdef UVM_ENABLE_DEPRECATED_API + if (uvm_default_printer == null) begin + uvm_default_printer = uvm_table_printer::get_default() ; + end + return uvm_default_printer ; +`else + if (m_printer == null) begin + m_printer = uvm_table_printer::get_default() ; + end + return m_printer ; +`endif + endfunction + + local uvm_packer m_packer ; + + virtual function void set_default_packer(uvm_packer packer); +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_default_packer = packer ; +`else + m_packer = packer ; + +`endif + endfunction + + virtual function uvm_packer get_default_packer(); +`ifdef UVM_ENABLE_DEPRECATED_API + if (uvm_default_packer == null) begin + uvm_default_packer = new() ; + end + return uvm_default_packer ; +`else + if (m_packer == null) begin + m_packer = new("uvm_default_packer") ; + end + return m_packer ; +`endif + endfunction + + local uvm_comparer m_comparer ; + virtual function void set_default_comparer(uvm_comparer comparer); +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_default_comparer = comparer ; +`else + m_comparer = comparer ; +`endif + endfunction + virtual function uvm_comparer get_default_comparer(); +`ifdef UVM_ENABLE_DEPRECATED_API + if (uvm_default_comparer == null) begin + uvm_default_comparer = new() ; + end + return uvm_default_comparer ; +`else + if (m_comparer == null) begin + m_comparer = new("uvm_default_comparer") ; + end + return m_comparer ; +`endif + endfunction + + local int m_default_max_ready_to_end_iters = 20; + virtual function void set_phase_max_ready_to_end(int max); + m_default_max_ready_to_end_iters = max; + endfunction + + virtual function int get_phase_max_ready_to_end(); + return m_default_max_ready_to_end_iters; + endfunction + + local uvm_resource_pool m_rp ; + virtual function void set_resource_pool (uvm_resource_pool pool); + m_rp = pool; + endfunction + + virtual function uvm_resource_pool get_resource_pool(); + if(m_rp == null) + m_rp = new(); + return m_rp; + endfunction + + local int unsigned m_default_precedence = 1000; + virtual function void set_resource_pool_default_precedence(int unsigned precedence); + m_default_precedence = precedence; + endfunction + + virtual function int unsigned get_resource_pool_default_precedence(); + return m_default_precedence; + endfunction + + local int unsigned m_uvm_global_seed = $urandom; + virtual function int unsigned get_global_seed(); + return m_uvm_global_seed; + endfunction + +`ifndef UVM_ENABLE_DEPRECATED_API + // This bit is located in uvm_object in deprecated mode + local bit m_use_uvm_seeding = 1; +`endif + + // @uvm-ieee 1800.2-2017 auto F.4.3 + virtual function bit get_uvm_seeding(); +`ifdef UVM_ENABLE_DEPRECATED_API + return uvm_object::use_uvm_seeding; +`else + return m_use_uvm_seeding; +`endif + endfunction : get_uvm_seeding + + // @uvm-ieee 1800.2-2017 auto F.4.4 + virtual function void set_uvm_seeding(bit enable); +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_object::use_uvm_seeding = enable; +`else + m_use_uvm_seeding = enable; `endif + endfunction : set_uvm_seeding - // UVM ~ - static function uvm_coreservice_t get(); - //UVM if(inst==null) - //UVM uvm_init(null); - if(inst==null) - inst = new; - //UVM + local uvm_copier m_copier ; - return inst; - endfunction // get + virtual function void set_default_copier(uvm_copier copier); + m_copier = copier ; + endfunction + virtual function uvm_copier get_default_copier(); + if (m_copier == null) begin + m_copier = new("uvm_default_copier") ; + end + return m_copier ; + endfunction - // UVM 1:1 - virtual function uvm_root get_root(); - return uvm_root::m_uvm_get_root(); - endfunction endclass diff --git a/test_regress/t/t_uvm/base/uvm_domain.svh b/test_regress/t/t_uvm/base/uvm_domain.svh index d894177f54..88903bcb31 100644 --- a/test_regress/t/t_uvm/base/uvm_domain.svh +++ b/test_regress/t/t_uvm/base/uvm_domain.svh @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 // //---------------------------------------------------------------------- // Copyright 2007-2018 Mentor Graphics Corporation @@ -23,43 +22,38 @@ // permissions and limitations under the License. //---------------------------------------------------------------------- -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- - -//UVM typedef class uvm_build_phase; -//UVM typedef class uvm_connect_phase; -//UVM typedef class uvm_end_of_elaboration_phase; -//UVM typedef class uvm_start_of_simulation_phase; -//UVM typedef class uvm_run_phase; -//UVM typedef class uvm_extract_phase; -//UVM typedef class uvm_check_phase; -//UVM typedef class uvm_report_phase; -//UVM typedef class uvm_final_phase; -//UVM -//UVM typedef class uvm_pre_reset_phase; -//UVM typedef class uvm_reset_phase; -//UVM typedef class uvm_post_reset_phase; -//UVM typedef class uvm_pre_configure_phase; -//UVM typedef class uvm_configure_phase; -//UVM typedef class uvm_post_configure_phase; -//UVM typedef class uvm_pre_main_phase; -//UVM typedef class uvm_main_phase; -//UVM typedef class uvm_post_main_phase; -//UVM typedef class uvm_pre_shutdown_phase; -//UVM typedef class uvm_shutdown_phase; -//UVM typedef class uvm_post_shutdown_phase; -//UVM -//UVM uvm_phase build_ph; -//UVM uvm_phase connect_ph; -//UVM uvm_phase end_of_elaboration_ph; -//UVM uvm_phase start_of_simulation_ph; -//UVM uvm_phase run_ph; -//UVM uvm_phase extract_ph; -//UVM uvm_phase check_ph; -//UVM uvm_phase report_ph; - +typedef class uvm_build_phase; +typedef class uvm_connect_phase; +typedef class uvm_end_of_elaboration_phase; +typedef class uvm_start_of_simulation_phase; +typedef class uvm_run_phase; +typedef class uvm_extract_phase; +typedef class uvm_check_phase; +typedef class uvm_report_phase; +typedef class uvm_final_phase; + +typedef class uvm_pre_reset_phase; +typedef class uvm_reset_phase; +typedef class uvm_post_reset_phase; +typedef class uvm_pre_configure_phase; +typedef class uvm_configure_phase; +typedef class uvm_post_configure_phase; +typedef class uvm_pre_main_phase; +typedef class uvm_main_phase; +typedef class uvm_post_main_phase; +typedef class uvm_pre_shutdown_phase; +typedef class uvm_shutdown_phase; +typedef class uvm_post_shutdown_phase; + +uvm_phase build_ph; +uvm_phase connect_ph; +uvm_phase end_of_elaboration_ph; +uvm_phase start_of_simulation_ph; +uvm_phase run_ph; +uvm_phase extract_ph; +uvm_phase check_ph; +uvm_phase report_ph; + //------------------------------------------------------------------------------ // // Class -- NODOCS -- uvm_domain @@ -77,18 +71,12 @@ class uvm_domain extends uvm_phase; static local uvm_domain m_domains[string]; static local uvm_phase m_uvm_schedule; -//UVM - static function uvmt_drop_globals(); - m_uvm_domain = null; - m_domains.delete(); - m_uvm_schedule = null; - endfunction -//UVM + // @uvm-ieee 1800.2-2017 auto 9.4.2.2 static function void get_domains(output uvm_domain domains[string]); domains = m_domains; - endfunction + endfunction // Function -- NODOCS -- get_uvm_schedule @@ -99,7 +87,7 @@ class uvm_domain extends uvm_phase; static function uvm_phase get_uvm_schedule(); void'(get_uvm_domain()); return m_uvm_schedule; - endfunction + endfunction // Function -- NODOCS -- get_common_domain @@ -115,37 +103,36 @@ class uvm_domain extends uvm_phase; if(m_domains.exists("common")) domain = m_domains["common"]; - + if (domain != null) return domain; domain = new("common"); -//UVM domain.add(uvm_build_phase::get()); -//UVM domain.add(uvm_connect_phase::get()); -//UVM domain.add(uvm_end_of_elaboration_phase::get()); -//UVM domain.add(uvm_start_of_simulation_phase::get()); -//UVM domain.add(uvm_run_phase::get()); -//UVM domain.add(uvm_extract_phase::get()); -//UVM domain.add(uvm_check_phase::get()); -//UVM domain.add(uvm_report_phase::get()); -//UVM domain.add(uvm_final_phase::get()); -//UVM -//UVM // for backward compatibility, make common phases visible; -//UVM // same as uvm__phase::get(). -//UVM build_ph = domain.find(uvm_build_phase::get()); -//UVM connect_ph = domain.find(uvm_connect_phase::get()); -//UVM end_of_elaboration_ph = domain.find(uvm_end_of_elaboration_phase::get()); -//UVM start_of_simulation_ph = domain.find(uvm_start_of_simulation_phase::get()); -//UVM run_ph = domain.find(uvm_run_phase::get()); -//UVM extract_ph = domain.find(uvm_extract_phase::get()); -//UVM check_ph = domain.find(uvm_check_phase::get()); -//UVM report_ph = domain.find(uvm_report_phase::get()); + domain.add(uvm_build_phase::get()); + domain.add(uvm_connect_phase::get()); + domain.add(uvm_end_of_elaboration_phase::get()); + domain.add(uvm_start_of_simulation_phase::get()); + domain.add(uvm_run_phase::get()); + domain.add(uvm_extract_phase::get()); + domain.add(uvm_check_phase::get()); + domain.add(uvm_report_phase::get()); + domain.add(uvm_final_phase::get()); + + // for backward compatibility, make common phases visible; + // same as uvm__phase::get(). + build_ph = domain.find(uvm_build_phase::get()); + connect_ph = domain.find(uvm_connect_phase::get()); + end_of_elaboration_ph = domain.find(uvm_end_of_elaboration_phase::get()); + start_of_simulation_ph = domain.find(uvm_start_of_simulation_phase::get()); + run_ph = domain.find(uvm_run_phase::get()); + extract_ph = domain.find(uvm_extract_phase::get()); + check_ph = domain.find(uvm_check_phase::get()); + report_ph = domain.find(uvm_report_phase::get()); domain = get_uvm_domain(); -//UVM m_domains["common"].add(domain, -//UVM .with_phase(m_domains["common"].find(uvm_run_phase::get()))); -// Temporarily remove default run phase -//UVM + m_domains["common"].add(domain, + .with_phase(m_domains["common"].find(uvm_run_phase::get()))); + return m_domains["common"]; @@ -155,21 +142,19 @@ class uvm_domain extends uvm_phase; // @uvm-ieee 1800.2-2017 auto 9.4.2.3 static function void add_uvm_phases(uvm_phase schedule); -//UVM - $display("[uvm]: WARNING: add_uvm_phases is a stub"); -//UVM -//UVM schedule.add(uvm_pre_reset_phase::get()); -//UVM schedule.add(uvm_reset_phase::get()); -//UVM schedule.add(uvm_post_reset_phase::get()); -//UVM schedule.add(uvm_pre_configure_phase::get()); -//UVM schedule.add(uvm_configure_phase::get()); -//UVM schedule.add(uvm_post_configure_phase::get()); -//UVM schedule.add(uvm_pre_main_phase::get()); -//UVM schedule.add(uvm_main_phase::get()); -//UVM schedule.add(uvm_post_main_phase::get()); -//UVM schedule.add(uvm_pre_shutdown_phase::get()); -//UVM schedule.add(uvm_shutdown_phase::get()); -//UVM schedule.add(uvm_post_shutdown_phase::get()); + + schedule.add(uvm_pre_reset_phase::get()); + schedule.add(uvm_reset_phase::get()); + schedule.add(uvm_post_reset_phase::get()); + schedule.add(uvm_pre_configure_phase::get()); + schedule.add(uvm_configure_phase::get()); + schedule.add(uvm_post_configure_phase::get()); + schedule.add(uvm_pre_main_phase::get()); + schedule.add(uvm_main_phase::get()); + schedule.add(uvm_post_main_phase::get()); + schedule.add(uvm_pre_shutdown_phase::get()); + schedule.add(uvm_shutdown_phase::get()); + schedule.add(uvm_post_shutdown_phase::get()); endfunction @@ -179,12 +164,12 @@ class uvm_domain extends uvm_phase; // Get a handle to the singleton ~uvm~ domain // static function uvm_domain get_uvm_domain(); - + if (m_uvm_domain == null) begin m_uvm_domain = new("uvm"); m_uvm_schedule = new("uvm_sched", UVM_PHASE_SCHEDULE); add_uvm_phases(m_uvm_schedule); -//UVM m_uvm_domain.add(m_uvm_schedule); + m_uvm_domain.add(m_uvm_schedule); end return m_uvm_domain; endfunction @@ -205,24 +190,24 @@ class uvm_domain extends uvm_phase; uvm_phase phases[$]; m_get_transitive_children(phases); - - phases = phases.find(item) with (item.get_state() inside {[UVM_PHASE_STARTED:UVM_PHASE_CLEANUP]}); - - foreach(phases[idx]) + + phases = phases.find(item) with (item.get_state() inside {[UVM_PHASE_STARTED:UVM_PHASE_CLEANUP]}); + + foreach(phases[idx]) if(phases[idx].is_before(phase) || phases[idx].is_after(phase)) - phases[idx].jump(phase); - + phases[idx].jump(phase); + endfunction // jump_all // -------- static function void jump_all(uvm_phase phase); uvm_domain domains[string]; - + uvm_domain::get_domains(domains); - - foreach(domains[idx]) - domains[idx].jump(phase); - + + foreach(domains[idx]) + domains[idx].jump(phase); + endfunction endclass diff --git a/test_regress/t/t_uvm/base/uvm_event.svh b/test_regress/t/t_uvm/base/uvm_event.svh new file mode 100644 index 0000000000..c4701631ae --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_event.svh @@ -0,0 +1,451 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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-2017 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-2017 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-2017 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-2017 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-2017 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-2017 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-2017 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-2017 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-2017 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-2017 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-2017 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 -- NODOCS -- 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. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 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; + 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-2017 auto 10.1.2.2.1 + function new (string name=""); + super.new(name); + endfunction + + // Task -- NODOCS -- wait_trigger_data + // + // This method calls followed by . + + // @uvm-ieee 1800.2-2017 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-2017 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-2017 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 + ->m_event; + foreach (cb_q[i]) + cb_q[i].post_trigger(this, data); + num_waiters = 0; + on = 1; + trigger_time = $realtime; + trigger_data = data; + end + endfunction + + + // Function -- NODOCS -- get_trigger_data + // + // Gets the data, if any, provided by the last call to . + + // @uvm-ieee 1800.2-2017 auto 10.1.2.2.5 + virtual function T get_trigger_data (); + return trigger_data; + endfunction + + // Function -- NODOCS -- default data + + // @uvm-ieee 1800.2-2017 auto 10.1.2.2.6 + virtual function T get_default_data(); + return default_data; + endfunction : get_default_data + + // @uvm-ieee 1800.2-2017 auto 10.1.2.2.6 + virtual function void set_default_data(T data); + default_data = data; + endfunction : set_default_data + +`ifdef UVM_ENABLE_DEPRECATED_API + //-----------// + // callbacks // + //-----------// + + // Function -- NODOCS -- 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 add_callback (uvm_event_callback#(T) cb, bit append=1); + if (append) + cbs_type::add(this, cb, UVM_APPEND); + else + cbs_type::add(this, cb, UVM_PREPEND); + endfunction + + + // Function -- NODOCS -- delete_callback + // + // Unregisters the given callback, ~cb~, from this event. + + virtual function void delete_callback (uvm_event_callback#(T) cb); + cbs_type::delete(this, cb); + endfunction // delete_callback +`endif + + 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 diff --git a/test_regress/t/t_uvm/base/uvm_event_callback.svh b/test_regress/t/t_uvm/base/uvm_event_callback.svh new file mode 100644 index 0000000000..2f07a44c05 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_event_callback.svh @@ -0,0 +1,94 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 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. +//------------------------------------------------------------------------------ + +typedef class uvm_object; +typedef class uvm_event; +typedef class uvm_callback; +typedef class uvm_callbacks; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_event_callback +// +// The uvm_event_callback class is an abstract class that is used to create +// callback objects which may be attached to s. To use, you +// derive a new class and override any or both and . +// +// Callbacks are an alternative to using processes that wait on events. When a +// callback is attached to an event, that callback object's callback function +// is called each time the event is triggered. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 10.2.1 +virtual class uvm_event_callback#(type T=uvm_object) extends uvm_callback; + + // Function -- NODOCS -- new + // + // Creates a new callback object. + + // @uvm-ieee 1800.2-2017 auto 10.2.2.1 + function new (string name=""); + super.new(name); + endfunction + + + // Function -- NODOCS -- pre_trigger + // + // This callback is called just before triggering the associated event. + // In a derived class, override this method to implement any pre-trigger + // functionality. + // + // If your callback returns 1, then the event will not trigger and the + // post-trigger callback is not called. This provides a way for a callback + // to prevent the event from triggering. + // + // In the function, ~e~ is the that is being triggered, and ~data~ + // is the optional data associated with the event trigger. + + // @uvm-ieee 1800.2-2017 auto 10.2.2.2 + virtual function bit pre_trigger (uvm_event#(T) e, T data); + return 0; + endfunction + + + // Function -- NODOCS -- post_trigger + // + // This callback is called after triggering the associated event. + // In a derived class, override this method to implement any post-trigger + // functionality. + // + // + // In the function, ~e~ is the that is being triggered, and ~data~ + // is the optional data associated with the event trigger. + + // @uvm-ieee 1800.2-2017 auto 10.2.2.3 + virtual function void post_trigger (uvm_event#(T) e, T data); + return; + endfunction + + + virtual function uvm_object create (string name=""); + return null; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_factory.svh b/test_regress/t/t_uvm/base/uvm_factory.svh new file mode 100644 index 0000000000..a1b1834145 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_factory.svh @@ -0,0 +1,2107 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Semifore +// Copyright 2017 Intel Corporation +// Copyright 2018 Qualcomm, Inc. +// Copyright 2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013 Verilab +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//------------------------------------------------------------------------------ + + +typedef class uvm_object; +typedef class uvm_component; +typedef class uvm_object_wrapper; +typedef class uvm_factory_override; +typedef struct {uvm_object_wrapper m_type; + string m_type_name;} m_uvm_factory_type_pair_t; +//Instance overrides by requested type lookup +class uvm_factory_queue_class; + uvm_factory_override queue[$]; +endclass + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- UVM Factory +// +// This page covers the classes that define the UVM factory facility. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_factory +// +//------------------------------------------------------------------------------ +// +// As the name implies, uvm_factory is used to manufacture (create) UVM objects +// and components. Object and component types are registered +// with the factory using lightweight proxies to the actual objects and +// components being created. The and +// class are used to proxy +// and . +// +// The factory provides both name-based and type-based interfaces. +// +// type-based - The type-based interface is far less prone to errors in usage. +// When errors do occur, they are caught at compile-time. +// +// name-based - The name-based interface is dominated +// by string arguments that can be misspelled and provided in the wrong order. +// Errors in name-based requests might only be caught at the time of the call, +// if at all. Further, the name-based interface is not portable across +// simulators when used with parameterized classes. +// +// +// The ~uvm_factory~ is an abstract class which declares many of its methods +// as ~pure virtual~. The UVM uses the class +// as its default factory implementation. +// +// See section for details on configuring and using the factory. +// + +// @uvm-ieee 1800.2-2017 auto 8.3.1.1 +virtual class uvm_factory; + + // Group -- NODOCS -- Retrieving the factory + + + + // @uvm-ieee 1800.2-2017 auto 8.3.1.2.1 + static function uvm_factory get(); + uvm_coreservice_t s; + s = uvm_coreservice_t::get(); + return s.get_factory(); + endfunction + + // @uvm-ieee 1800.2-2017 auto 8.3.1.2.2 + static function void set(uvm_factory f); + uvm_coreservice_t s; + s = uvm_coreservice_t::get(); + s.set_factory(f); + endfunction + + // Group -- NODOCS -- Registering Types + + // Function -- NODOCS -- register + // + // Registers the given proxy object, ~obj~, with the factory. The proxy object + // is a lightweight substitute for the component or object it represents. When + // the factory needs to create an object of a given type, it calls the proxy's + // create_object or create_component method to do so. + // + // When doing name-based operations, the factory calls the proxy's + // ~get_type_name~ method to match against the ~requested_type_name~ argument in + // subsequent calls to and . + // If the proxy object's ~get_type_name~ method returns the empty string, + // name-based lookup is effectively disabled. + + // @uvm-ieee 1800.2-2017 auto 8.3.1.3 + pure virtual function void register (uvm_object_wrapper obj); + + + // Group -- NODOCS -- Type & Instance Overrides + + // Function -- NODOCS -- set_inst_override_by_type + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.4.1 + void set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + + // Function -- NODOCS -- set_inst_override_by_name + // + // Configures the factory to create an object of the override's type whenever + // a request is made to create an object of the original type using a context + // that matches ~full_inst_path~. The original type is typically a super class + // of the override type. + // + // When overriding by type, the ~original_type~ and ~override_type~ are + // handles to the types' proxy objects. Preregistration is not required. + // + // When overriding by name, the ~original_type_name~ typically refers to a + // preregistered type in the factory. It may, however, be any arbitrary + // string. Future calls to any of the ~create_*~ methods with the same string + // and matching instance path will produce the type represented by + // ~override_type_name~, which must be preregistered with the factory. + // + // The ~full_inst_path~ is matched against the concatenation of + // {~parent_inst_path~, ".", ~name~} provided in future create requests. The + // ~full_inst_path~ may include wildcards (* and ?) such that a single + // instance override can be applied in multiple contexts. A ~full_inst_path~ + // of "*" is effectively a type override, as it will match all contexts. + // + // When the factory processes instance overrides, the instance queue is + // processed in order of override registrations, and the first override + // match prevails. Thus, more specific overrides should be registered + // first, followed by more general overrides. + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.4.1 + void set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + + + // Function -- NODOCS -- set_type_override_by_type + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.4.2 + void set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + + // Function -- NODOCS -- set_type_override_by_name + // + // Configures the factory to create an object of the override's type whenever + // a request is made to create an object of the original type, provided no + // instance override applies. The original type is typically a super class of + // the override type. + // + // When overriding by type, the ~original_type~ and ~override_type~ are + // handles to the types' proxy objects. Preregistration is not required. + // + // When overriding by name, the ~original_type_name~ typically refers to a + // preregistered type in the factory. It may, however, be any arbitrary + // string. Future calls to any of the ~create_*~ methods with the same string + // and matching instance path will produce the type represented by + // ~override_type_name~, which must be preregistered with the factory. + // + // When ~replace~ is 1, a previous override on ~original_type_name~ is + // replaced, otherwise a previous override, if any, remains intact. + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.4.2 + void set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + + + // Group -- NODOCS -- Creation + + // Function -- NODOCS -- create_object_by_type + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.5 + uvm_object create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + + // Function -- NODOCS -- create_component_by_type + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.5 + uvm_component create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + + // Function -- NODOCS -- create_object_by_name + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.5 + uvm_object create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + + // Function -- NODOCS -- is_type_name_registered + + pure virtual + // @uvm-ieee 1800.2-2017 auto 8.3.1.7.3 + function bit is_type_name_registered (string type_name); + + + // Function -- NODOCS -- is_type_registered + + pure virtual + // @uvm-ieee 1800.2-2017 auto 8.3.1.7.4 + function bit is_type_registered (uvm_object_wrapper obj); + + + // + // Creates and returns a component or object of the requested type, which may + // be specified by type or by name. A requested component must be derived + // from the base class, and a requested object must be derived + // from the base class. + // + // When requesting by type, the ~requested_type~ is a handle to the type's + // proxy object. Preregistration is not required. + // + // When requesting by name, the ~request_type_name~ is a string representing + // the requested type, which must have been registered with the factory with + // that name prior to the request. If the factory does not recognize the + // ~requested_type_name~, an error is produced and a ~null~ handle returned. + // + // If the optional ~parent_inst_path~ is provided, then the concatenation, + // {~parent_inst_path~, ".",~name~}, forms an instance path (context) that + // is used to search for an instance override. The ~parent_inst_path~ is + // typically obtained by calling the on the + // parent. + // + // If no instance override is found, the factory then searches for a type + // override. + // + // Once the final override is found, an instance of that component or object + // is returned in place of the requested type. New components will have the + // given ~name~ and ~parent~. New objects will have the given ~name~, if + // provided. + // + // Override searches are recursively applied, with instance overrides taking + // precedence over type overrides. If ~foo~ overrides ~bar~, and ~xyz~ + // overrides ~foo~, then a request for ~bar~ will produce ~xyz~. Recursive + // loops will result in an error, in which case the type returned will be + // that which formed the loop. Using the previous example, if ~bar~ + // overrides ~xyz~, then ~bar~ is returned after the error is issued. + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.5 + uvm_component create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + + // Group -- NODOCS -- Name Aliases + + // Function -- NODOCS -- set_type_alias + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.6.1 + void set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + + //Intended to allow overrides by type to use the alias_type_name as an additional name to refer to + //original_type + + // Function -- NODOCS -- set_inst_alias + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.6.2 + void set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + + //Intended to allow overrides by name to use the alias_type_name as an additional name to refer to + //original_type in the context referred to by full_inst_path. + + + // Group -- NODOCS -- Debug + + // Function -- NODOCS -- debug_create_by_type + + pure virtual function + void debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + + // Function -- NODOCS -- debug_create_by_name + // + // These methods perform the same search algorithm as the ~create_*~ methods, + // but they do not create new objects. Instead, they provide detailed + // information about what type of object it would return, listing each + // override that was applied to arrive at the result. Interpretation of the + // arguments are exactly as with the ~create_*~ methods. + + pure virtual function + void debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + + + // Function -- NODOCS -- find_override_by_type + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.7.1 + uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, + string full_inst_path); + + // Function -- NODOCS -- find_override_by_name + // + // These methods return the proxy to the object that would be created given + // the arguments. The ~full_inst_path~ is typically derived from the parent's + // instance path and the leaf name of the object to be created, i.e. + // { parent.get_full_name(), ".", name }. + + pure virtual function + // @uvm-ieee 1800.2-2017 auto 8.3.1.7.1 + uvm_object_wrapper find_override_by_name (string requested_type_name, + string full_inst_path); + + // Function -- NODOCS -- find_wrapper_by_name + // + // This method returns the associated with a given + // ~type_name~. + pure virtual + // @uvm-ieee 1800.2-2017 auto 8.3.1.7.2 + function uvm_object_wrapper find_wrapper_by_name (string type_name); + + // Function -- NODOCS -- print + // + // Prints the state of the uvm_factory, including registered types, instance + // overrides, and type overrides. + // + // When ~all_types~ is 0, only type and instance overrides are displayed. When + // ~all_types~ is 1 (default), all registered user-defined types are printed as + // well, provided they have names associated with them. When ~all_types~ is 2, + // the UVM types (prefixed with uvm_) are included in the list of registered + // types. + + // @uvm-ieee 1800.2-2017 auto 8.3.1.7.5 + pure virtual function void print (int all_types=1); +endclass + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_default_factory +// +//------------------------------------------------------------------------------ +// +// Default implementation of the UVM factory. The library implements the +// following public API beyond what is documented in IEEE 1800.2. + +// @uvm-ieee 1800.2-2017 auto 8.3.3 +class uvm_default_factory extends uvm_factory; + + // Group --NODOCS-- Registering Types + + // Function --NODOCS-- register + // + // Registers the given proxy object, ~obj~, with the factory. + + extern virtual function void register (uvm_object_wrapper obj); + + + // Group --NODOCS-- Type & Instance Overrides + + // Function --NODOCS-- set_inst_override_by_type + + extern virtual function + void set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + + // Function --NODOCS-- set_inst_override_by_name + // + // Configures the factory to create an object of the override's type whenever + // a request is made to create an object of the original type using a context + // that matches ~full_inst_path~. + // + // ~original_type_name~ may be the factory-registered type name or an aliased name + // specified with in the context of ~full_inst_path~. + extern virtual function + void set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + + + // Function --NODOCS-- set_type_override_by_type + + extern virtual function + void set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + + // Function --NODOCS-- set_type_override_by_name + // + // Configures the factory to create an object of the override's type whenever + // a request is made to create an object of the original type, provided no + // instance override applies. + // + // ~original_type_name~ may be the factory-registered type name or an aliased name + // specified with . + + extern virtual function + void set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + + // Function --NODOCS-- set_type_alias + // + // Intended to allow overrides by type to use the alias_type_name as an additional name to refer to + // original_type + + extern virtual function + void set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + + // Function --NODOCS-- set_inst_alias + // + // Intended to allow overrides by name to use the alias_type_name as an additional name to refer to + // original_type in the context referred to by full_inst_path. + + extern virtual function + void set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + + + + // Group --NODOCS-- Creation + + // Function --NODOCS-- create_object_by_type + + extern virtual function + uvm_object create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + + // Function --NODOCS-- create_component_by_type + + extern virtual function + uvm_component create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + + // Function --NODOCS-- create_object_by_name + + extern virtual function + uvm_object create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + + // Function --NODOCS-- create_component_by_name + // + // Creates and returns a component or object of the requested type, which may + // be specified by type or by name. + + extern virtual function + uvm_component create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + + // Function --NODOCS-- is_type_name_registered + // + // silently check type with a given name was registered in the factory or not + + extern virtual + function bit is_type_name_registered (string type_name); + + + // Function --NODOCS-- is_type_registered + // + // silently check type is registered in the factory or not + + extern virtual + function bit is_type_registered (uvm_object_wrapper obj); + + + // Function: debug_create_by_type + // Debug traces for ~create_*_by_type~ methods. + // + // This method performs the same search algorithm as the and + // methods, however instead of creating the new object or component, + // the method shall generate a report message detailing how the object or component would + // have been constructed after all overrides are accounted for. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + extern virtual function + void debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + + // Function: debug_create_by_name + // Debug traces for ~create_*_by_name~ methods. + // + // This method performs the same search algorithm as the and + // methods, however instead of creating the new object or component, + // the method shall generate a report message detailing how the object or component would + // have been constructed after all overrides are accounted for. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + extern virtual function + void debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + + + // Function --NODOCS-- find_override_by_type + + extern virtual function + uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, + string full_inst_path); + + // Function --NODOCS-- find_override_by_name + // + // These methods return the proxy to the object that would be created given + // the arguments. + + extern virtual function + uvm_object_wrapper find_override_by_name (string requested_type_name, + string full_inst_path); + + extern virtual + function uvm_object_wrapper find_wrapper_by_name (string type_name); + + // Function --NODOCS-- print + // + // Prints the state of the uvm_factory, including registered types, instance + // overrides, and type overrides. + // + extern virtual function void print (int all_types=1); + + + //---------------------------------------------------------------------------- + // PRIVATE MEMBERS + + extern protected + function void m_debug_create (string requested_type_name, + uvm_object_wrapper requested_type, + string parent_inst_path, + string name); + + extern protected + function void m_debug_display(string requested_type_name, + uvm_object_wrapper result, + string full_inst_path); + + extern + function uvm_object_wrapper m_resolve_type_name(string requested_type_name); + + extern + function uvm_object_wrapper m_resolve_type_name_by_inst(string requested_type_name, + string full_inst_path); + + extern + function bit m_matches_type_pair(m_uvm_factory_type_pair_t match_type_pair, + uvm_object_wrapper requested_type, + string requested_type_name); + + extern + function bit m_matches_type_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path="", + bit match_original_type = 1, + bit resolve_null_type_by_inst=0); + extern + function bit m_matches_inst_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path=""); + + typedef struct { + m_uvm_factory_type_pair_t orig; + string alias_type_name; + string full_inst_path; + } m_inst_typename_alias_t; + + protected bit m_types[uvm_object_wrapper]; + protected bit m_lookup_strs[string]; + protected uvm_object_wrapper m_type_names[string]; + protected m_inst_typename_alias_t m_inst_aliases[$]; + + protected uvm_factory_override m_type_overrides[$]; + protected uvm_factory_override m_inst_overrides[$]; + + + local uvm_factory_override m_override_info[$]; + local static bit m_debug_pass; + + + extern function bit check_inst_override_exists + (uvm_object_wrapper original_type, + string original_type_name, + uvm_object_wrapper override_type, + string override_type_name, + string full_inst_path); + +endclass + + +//------------------------------------------------------------------------------ +// +// Group -- NODOCS -- Usage +// +// Using the factory involves three basic operations +// +// 1 - Registering objects and components types with the factory +// 2 - Designing components to use the factory to create objects or components +// 3 - Configuring the factory with type and instance overrides, both within and +// outside components +// +// We'll briefly cover each of these steps here. More reference information can +// be found at , , +// , . +// +// 1 -- Registering objects and component types with the factory: +// +// When defining and -based classes, simply invoke +// the appropriate macro. Use of macros are required to ensure portability +// across different vendors' simulators. +// +// Objects that are not parameterized are declared as +// +//| class packet extends uvm_object; +//| `uvm_object_utils(packet) +//| endclass +//| +//| class packetD extends packet; +//| `uvm_object_utils(packetD) +//| endclass +// +// Objects that are parameterized are declared as +// +//| class packet #(type T=int, int WIDTH=32) extends uvm_object; +//| `uvm_object_param_utils(packet #(T,WIDTH)) +//| endclass +// +// Components that are not parameterized are declared as +// +//| class comp extends uvm_component; +//| `uvm_component_utils(comp) +//| endclass +// +// Components that are parameterized are declared as +// +//| class comp #(type T=int, int WIDTH=32) extends uvm_component; +//| `uvm_component_param_utils(comp #(T,WIDTH)) +//| endclass +// +// The `uvm_*_utils macros for simple, non-parameterized classes will register +// the type with the factory and define the get_type, get_type_name, and create +// virtual methods inherited from . It will also define a static +// type_name variable in the class, which will allow you to determine the type +// without having to allocate an instance. +// +// The `uvm_*_param_utils macros for parameterized classes differ from +// `uvm_*_utils classes in the following ways: +// +// - The ~get_type_name~ method and static type_name variable are not defined. You +// will need to implement these manually. +// +// - A type name is not associated with the type when registering with the +// factory, so the factory's *_by_name operations will not work with +// parameterized classes. +// +// - The factory's , , and +// methods, which depend on type names to convey information, will list +// parameterized types as ''. +// +// It is worth noting that environments that exclusively use the type-based +// factory methods (*_by_type) do not require type registration. The factory's +// type-based methods will register the types involved "on the fly," when first +// used. However, registering with the `uvm_*_utils macros enables name-based +// factory usage and implements some useful utility functions. +// +// +// 2 -- Designing components that defer creation to the factory: +// +// Having registered your objects and components with the factory, you can now +// make requests for new objects and components via the factory. Using the factory +// instead of allocating them directly (via new) allows different objects to be +// substituted for the original without modifying the requesting class. The +// following code defines a driver class that is parameterized. +// +//| class driverB #(type T=uvm_object) extends uvm_driver; +//| +//| // parameterized classes must use the _param_utils version +//| `uvm_component_param_utils(driverB #(T)) +//| +//| // our packet type; this can be overridden via the factory +//| T pkt; +//| +//| // standard component constructor +//| function new(string name, uvm_component parent=null); +//| super.new(name,parent); +//| endfunction +//| +//| // get_type_name not implemented by macro for parameterized classes +//| static function string type_name(); +//| return {"driverB #(",T::type_name(),")"}; +//| endfunction : type_name +//| virtual function string get_type_name(); +//| return type_name(); +//| endfunction +//| +//| // using the factory allows pkt overrides from outside the class +//| virtual function void build_phase(uvm_phase phase); +//| pkt = packet::type_id::create("pkt",this); +//| endfunction +//| +//| // print the packet so we can confirm its type when printing +//| virtual function void do_print(uvm_printer printer); +//| printer.print_object("pkt",pkt); +//| endfunction +//| +//| endclass +// +// For purposes of illustrating type and instance overrides, we define two +// subtypes of the ~driverB~ class. The subtypes are also parameterized, so +// we must again provide an implementation for , +// which we recommend writing in terms of a static string constant. +// +//| class driverD1 #(type T=uvm_object) extends driverB #(T); +//| +//| `uvm_component_param_utils(driverD1 #(T)) +//| +//| function new(string name, uvm_component parent=null); +//| super.new(name,parent); +//| endfunction +//| +//| static function string type_name(); +//| return {"driverD1 #(",T::type_name,")"}; +//| endfunction : type_name +//| virtual function string get_type_name(); +//| return type_name(); +//| endfunction +//| +//| endclass +//| +//| class driverD2 #(type T=uvm_object) extends driverB #(T); +//| +//| `uvm_component_param_utils(driverD2 #(T)) +//| +//| function new(string name, uvm_component parent=null); +//| super.new(name,parent); +//| endfunction +//| +//| static function string type_name(); +//| return {"driverD2 #(",T::type_name,")"}; +//| endfunction : type_name +//| virtual function string get_type_name(); +//| return type_name(); +//| endfunction +//| +//| endclass +//| +//| // typedef some specializations for convenience +//| typedef driverB #(packet) B_driver; // the base driver +//| typedef driverD1 #(packet) D1_driver; // a derived driver +//| typedef driverD2 #(packet) D2_driver; // another derived driver +// +// Next, we'll define a agent component, which requires a utils macro for +// non-parameterized types. Before creating the drivers using the factory, we +// override ~driver0~'s packet type to be ~packetD~. +// +//| class agent extends uvm_agent; +//| +//| `uvm_component_utils(agent) +//| ... +//| B_driver driver0; +//| B_driver driver1; +//| +//| function new(string name, uvm_component parent=null); +//| super.new(name,parent); +//| endfunction +//| +//| virtual function void build_phase(uvm_phase phase); +//| +//| // override the packet type for driver0 and below +//| packet::type_id::set_inst_override(packetD::get_type(),"driver0.*"); +//| +//| // create using the factory; actual driver types may be different +//| driver0 = B_driver::type_id::create("driver0",this); +//| driver1 = B_driver::type_id::create("driver1",this); +//| +//| endfunction +//| +//| endclass +// +// Finally we define an environment class, also not parameterized. Its ~build_phase~ +// method shows three methods for setting an instance override on a grandchild +// component with relative path name, ~agent1.driver1~, all equivalent. +// +//| class env extends uvm_env; +//| +//| `uvm_component_utils(env) +//| +//| agent agent0; +//| agent agent1; +//| +//| function new(string name, uvm_component parent=null); +//| super.new(name,parent); +//| endfunction +//| +//| virtual function void build_phase(uvm_phase phase); +//| +//| // three methods to set an instance override for agent1.driver1 +//| // - via component convenience method... +//| set_inst_override_by_type("agent1.driver1", +//| B_driver::get_type(), +//| D2_driver::get_type()); +//| +//| // - via the component's proxy (same approach as create)... +//| B_driver::type_id::set_inst_override(D2_driver::get_type(), +//| "agent1.driver1",this); +//| +//| // - via a direct call to a factory method... +//| factory.set_inst_override_by_type(B_driver::get_type(), +//| D2_driver::get_type(), +//| {get_full_name(),".agent1.driver1"}); +//| +//| // create agents using the factory; actual agent types may be different +//| agent0 = agent::type_id::create("agent0",this); +//| agent1 = agent::type_id::create("agent1",this); +//| +//| endfunction +//| +//| // at end_of_elaboration, print topology and factory state to verify +//| virtual function void end_of_elaboration_phase(uvm_phase phase); +//| uvm_top.print_topology(); +//| endfunction +//| +//| virtual task run_phase(uvm_phase phase); +//| #100 global_stop_request(); +//| endfunction +//| +//| endclass +// +// +// 3 -- Configuring the factory with type and instance overrides: +// +// In the previous step, we demonstrated setting instance overrides and creating +// components using the factory within component classes. Here, we will +// demonstrate setting overrides from outside components, as when initializing +// the environment prior to running the test. +// +//| module top; +//| +//| env env0; +//| +//| initial begin +//| +//| // Being registered first, the following overrides take precedence +//| // over any overrides made within env0's construction & build. +//| +//| // Replace all base drivers with derived drivers... +//| B_driver::type_id::set_type_override(D_driver::get_type()); +//| +//| // ...except for agent0.driver0, whose type remains a base driver. +//| // (Both methods below have the equivalent result.) +//| +//| // - via the component's proxy (preferred) +//| B_driver::type_id::set_inst_override(B_driver::get_type(), +//| "env0.agent0.driver0"); +//| +//| // - via a direct call to a factory method +//| factory.set_inst_override_by_type(B_driver::get_type(), +//| B_driver::get_type(), +//| {get_full_name(),"env0.agent0.driver0"}); +//| +//| // now, create the environment; our factory configuration will +//| // govern what topology gets created +//| env0 = new("env0"); +//| +//| // run the test (will execute build phase) +//| run_test(); +//| +//| end +//| +//| endmodule +// +// When the above example is run, the resulting topology (displayed via a call to +// in env's method) +// is similar to the following: +// +//| # UVM_INFO @ 0 [RNTST] Running test ... +//| # UVM_INFO @ 0 [UVMTOP] UVM testbench topology: +//| # ---------------------------------------------------------------------- +//| # Name Type Size Value +//| # ---------------------------------------------------------------------- +//| # env0 env - env0@2 +//| # agent0 agent - agent0@4 +//| # driver0 driverB #(packet) - driver0@8 +//| # pkt packet - pkt@21 +//| # driver1 driverD #(packet) - driver1@14 +//| # pkt packet - pkt@23 +//| # agent1 agent - agent1@6 +//| # driver0 driverD #(packet) - driver0@24 +//| # pkt packet - pkt@37 +//| # driver1 driverD2 #(packet) - driver1@30 +//| # pkt packet - pkt@39 +//| # ---------------------------------------------------------------------- +// +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_object_wrapper +// +// The uvm_object_wrapper provides an abstract interface for creating object and +// component proxies. Instances of these lightweight proxies, representing every +// -based and -based object available in the test +// environment, are registered with the . When the factory is +// called upon to create an object or component, it finds and delegates the +// request to the appropriate proxy. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 8.3.2.1 +virtual class uvm_object_wrapper; + + // Function -- NODOCS -- create_object + // + // Creates a new object with the optional ~name~. + // An object proxy (e.g., ) implements this + // method to create an object of a specific type, T. + + // @uvm-ieee 1800.2-2017 auto 8.3.2.2.1 + virtual function uvm_object create_object (string name=""); + return null; + endfunction + + + // Function -- NODOCS -- create_component + // + // Creates a new component, passing to its constructor the given ~name~ and + // ~parent~. A component proxy (e.g. ) + // implements this method to create a component of a specific type, T. + + // @uvm-ieee 1800.2-2017 auto 8.3.2.2.2 + virtual function uvm_component create_component (string name, + uvm_component parent); + return null; + endfunction + + + // Function -- NODOCS -- get_type_name + // + // Derived classes implement this method to return the type name of the object + // created by or . The factory uses this + // name when matching against the requested type in name-based lookups. + + // @uvm-ieee 1800.2-2017 auto 8.3.2.2.3 + pure virtual function string get_type_name(); + + virtual function void initialize(); endfunction +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS- uvm_factory_override +// +// Internal class. +//------------------------------------------------------------------------------ + +class uvm_factory_override; + + string full_inst_path; + m_uvm_factory_type_pair_t orig; + m_uvm_factory_type_pair_t ovrd; + bit replace; + bit selected; + int unsigned used; + bit has_wildcard; + + function new (string full_inst_path="", + string orig_type_name="", + uvm_object_wrapper orig_type=null, + uvm_object_wrapper ovrd_type, + string ovrd_type_name="", + bit replace=0); + + this.full_inst_path= full_inst_path; + this.orig.m_type_name = orig_type_name; + this.orig.m_type = orig_type; + this.ovrd.m_type_name = ovrd_type_name; + this.ovrd.m_type = ovrd_type; + this.replace = replace; + this.has_wildcard = m_has_wildcard(full_inst_path); + endfunction + + function bit m_has_wildcard(string nm); + foreach (nm[i]) + if(nm[i] == "*" || nm[i] == "?") return 1; + return 0; + endfunction + + +endclass + + +//----------------------------------------------------------------------------- +// IMPLEMENTATION +//----------------------------------------------------------------------------- + +// register +// -------- + +function void uvm_default_factory::register (uvm_object_wrapper obj); + + if (obj == null) begin + uvm_report_fatal ("NULLWR", "Attempting to register a null object with the factory", UVM_NONE); + end + if (obj.get_type_name() != "" && obj.get_type_name() != "") begin + if (m_type_names.exists(obj.get_type_name())) + uvm_report_warning("TPRGED", {"Type name '",obj.get_type_name(), + "' already registered with factory. No string-based lookup ", + "support for multiple types with the same type name."}, UVM_NONE); + else + m_type_names[obj.get_type_name()] = obj; + end + + if (m_types.exists(obj)) begin + if (obj.get_type_name() != "" && obj.get_type_name() != "") + uvm_report_warning("TPRGED", {"Object type '",obj.get_type_name(), + "' already registered with factory. "}, UVM_NONE); + end + else begin + uvm_factory_override overrides[$]; + m_types[obj] = 1; + // If a named override happens before the type is registered, need to update + // the override type + // Note:Registration occurs via static initialization, which occurs ahead of + // procedural (e.g. initial) blocks. There should not be any preexisting overrides. + overrides = {m_type_overrides, m_inst_overrides}; + foreach (overrides[index]) begin + if(m_matches_type_pair(.match_type_pair(overrides[index].orig), + .requested_type(null), + .requested_type_name(obj.get_type_name()))) begin + overrides[index].orig.m_type = obj; + end + if(m_matches_type_pair(.match_type_pair(overrides[index].ovrd), + .requested_type(null), + .requested_type_name(obj.get_type_name()))) begin + overrides[index].ovrd.m_type = obj; + end + end + end + +endfunction + + +// set_type_override_by_type +// ------------------------- + +function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + bit replaced; + + // check that old and new are not the same + if (original_type == override_type) begin + if (original_type.get_type_name() == "" || original_type.get_type_name() == "") + uvm_report_warning("TYPDUP", {"Original and override type ", + "arguments are identical"}, UVM_NONE); + else + uvm_report_warning("TYPDUP", {"Original and override type ", + "arguments are identical: ", + original_type.get_type_name()}, UVM_NONE); + end + + // register the types if not already done so, for the benefit of string-based lookup + if (!m_types.exists(original_type)) + register(original_type); + + if (!m_types.exists(override_type)) + register(override_type); + + + // check for existing type override + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(original_type), + .requested_type_name(original_type.get_type_name()))) begin + string msg; + msg = {"Original object type '",original_type.get_type_name(), + "' already registered to produce '", + m_type_overrides[index].ovrd.m_type_name,"'"}; + if (!replace) begin + msg = {msg, ". Set 'replace' argument to replace the existing entry."}; + uvm_report_info("TPREGD", msg, UVM_MEDIUM); + return; + end + msg = {msg, ". Replacing with override to produce type '", + override_type.get_type_name(),"'."}; + uvm_report_info("TPREGR", msg, UVM_MEDIUM); + replaced = 1; + m_type_overrides[index].orig.m_type = original_type; + m_type_overrides[index].orig.m_type_name = original_type.get_type_name(); + m_type_overrides[index].ovrd.m_type = override_type; + m_type_overrides[index].ovrd.m_type_name = override_type.get_type_name(); + m_type_overrides[index].replace = replace; + end + else if (m_type_overrides[index].orig.m_type == null) begin + // due to aliasing, optimizing around type override when the type is unknown could + // end up causing the wrong override to be returned as the type for the alias may + // resolve to match this existing override + break; + end + end + + // make a new entry + if (!replaced) begin + uvm_factory_override override; + override = new(.orig_type(original_type), + .orig_type_name(original_type.get_type_name()), + .ovrd_type(override_type), + .ovrd_type_name(override_type.get_type_name()), + .replace(replace)); + + m_type_overrides.push_front(override); + end + +endfunction + + +// set_type_override_by_name +// ------------------------- + +function void uvm_default_factory::set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + bit replaced; + + uvm_object_wrapper original_type; + uvm_object_wrapper override_type; + + if(m_type_names.exists(original_type_name)) + original_type = m_type_names[original_type_name]; + + if(m_type_names.exists(override_type_name)) + override_type = m_type_names[override_type_name]; + + + // check that type is registered with the factory +// aliasing feature makes this check invalid. Aliases +// aren't resolved until find/creation time so the type +// may resolve differently depending on the instance. +// if (override_type == null) begin +// uvm_report_error("TYPNTF", {"Cannot register override for original type '", +// original_type_name,"' because the override type '", +// override_type_name, "' is not registered with the factory."}, UVM_NONE); +// return; +// end + + // check that old and new are not the same + if (original_type_name == override_type_name) begin + uvm_report_warning("TYPDUP", {"Requested and actual type name ", + " arguments are identical: ",original_type_name,". Ignoring this override."}, UVM_NONE); + return; + end + + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(original_type), + .requested_type_name(original_type_name))) begin + if (!replace) begin + uvm_report_info("TPREGD", {"Original type '",original_type_name, "'/'",m_type_overrides[index].orig.m_type_name, + "' already registered to produce '",m_type_overrides[index].ovrd.m_type_name, + "'. Set 'replace' argument to replace the existing entry."}, UVM_MEDIUM); + return; + end + uvm_report_info("TPREGR", {"Original object type '",original_type_name, "'/'",m_type_overrides[index].orig.m_type_name, + "' already registered to produce '",m_type_overrides[index].ovrd.m_type_name, + "'. Replacing with override to produce type '",override_type_name,"'."}, UVM_MEDIUM); + replaced = 1; + m_type_overrides[index].ovrd.m_type = override_type; + m_type_overrides[index].ovrd.m_type_name = override_type_name; + m_type_overrides[index].replace = replace; + end + else if ((m_type_overrides[index].orig.m_type == null) || (original_type == null)) begin + // due to aliasing, optimizing around type override when the type is unknown could + // end up causing the wrong override to be returned as the type for the alias may + // resolve to match this existing override + break; + end + end + + if (original_type == null) + m_lookup_strs[original_type_name] = 1; + + if (!replaced) begin + uvm_factory_override override; + override = new(.orig_type(original_type), + .orig_type_name(original_type_name), + .ovrd_type(override_type), + .ovrd_type_name(override_type_name), + .replace(replace) + ); + + m_type_overrides.push_front(override); +// m_type_names[original_type_name] = override.ovrd_type; + end + +endfunction + + +// check_inst_override_exists +// -------------------------- +function bit uvm_default_factory::check_inst_override_exists (uvm_object_wrapper original_type, + string original_type_name, + uvm_object_wrapper override_type, + string override_type_name, + string full_inst_path); + uvm_factory_override override; + + + foreach (m_inst_overrides[i]) begin + + override = m_inst_overrides[i]; + if (override.full_inst_path == full_inst_path && + override.orig.m_type == original_type && + override.orig.m_type_name == original_type_name && + override.ovrd.m_type == override_type && + override.ovrd.m_type_name == override_type_name) begin + uvm_report_info("DUPOVRD",{"Instance override for '", + original_type_name,"' already exists: override type '", + override_type_name,"' with full_inst_path '", + full_inst_path,"'"},UVM_HIGH); + return 1; + end + end + return 0; +endfunction + +// set_inst_override_by_type +// ------------------------- + +function void uvm_default_factory::set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + + uvm_factory_override override; + + // register the types if not already done so + if (!m_types.exists(original_type)) + register(original_type); + + if (!m_types.exists(override_type)) + register(override_type); + + if (check_inst_override_exists(original_type, + original_type.get_type_name(), + override_type, + override_type.get_type_name(), + full_inst_path)) + return; + +// if(!m_inst_override_queues.exists(original_type)) +// m_inst_override_queues[original_type] = new; + + override = new(.full_inst_path(full_inst_path), + .orig_type(original_type), + .orig_type_name(original_type.get_type_name()), + .ovrd_type(override_type), + .ovrd_type_name(override_type.get_type_name())); + + m_inst_overrides.push_back(override); +// m_inst_override_queues[original_type].queue.push_back(override); + +endfunction + + +// set_inst_override_by_name +// ------------------------- + +function void uvm_default_factory::set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + + uvm_factory_override override; + uvm_object_wrapper original_type; + uvm_object_wrapper override_type; + + if(m_type_names.exists(original_type_name)) + original_type = m_type_names[original_type_name]; + + if(m_type_names.exists(override_type_name)) + override_type = m_type_names[override_type_name]; + + // check that type is registered with the factory +// aliasing feature makes this check invalid. Aliases +// aren't resolved until find/creation time so the type +// may resolve differently depending on the instance. +// if (override_type == null) begin +// uvm_report_error("TYPNTF", {"Cannot register instance override with type name '", +// original_type_name,"' and instance path '",full_inst_path,"' because the type it's supposed ", +// "to produce, '",override_type_name,"', is not registered with the factory."}, UVM_NONE); +// return; +// end + + if (original_type == null) + m_lookup_strs[original_type_name] = 1; + + override = new(.full_inst_path(full_inst_path), + .orig_type(original_type), + .orig_type_name(original_type_name), + .ovrd_type(override_type), + .ovrd_type_name(override_type_name)); + + if (check_inst_override_exists(original_type, + original_type_name, + override_type, + override_type_name, + full_inst_path)) + return; + + m_inst_overrides.push_back(override); + +endfunction + +//set_type_alias +// --------------------- + +function void uvm_default_factory::set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + if (!is_type_registered(original_type)) + uvm_report_warning("BDTYP",{"Cannot define alias of type '", + original_type.get_type_name(),"' because it is not registered with the factory."}, UVM_NONE); + else begin + if (!m_type_names.exists(alias_type_name)) begin + uvm_factory_override overrides[$]; + m_type_names[alias_type_name] = original_type; + // If a named override happens before the type alias is set, need to update + // the override type + overrides = {m_type_overrides, m_inst_overrides}; + foreach (overrides[index]) begin + if(m_matches_type_pair(.match_type_pair(overrides[index].orig), + .requested_type(null), + .requested_type_name(alias_type_name))) begin + overrides[index].orig.m_type = original_type; + end + if(m_matches_type_pair(.match_type_pair(overrides[index].ovrd), + .requested_type(null), + .requested_type_name(alias_type_name))) begin + overrides[index].ovrd.m_type = original_type; + end + end + end + end +endfunction + +// set_inst_alias +// --------------------- + +function void uvm_default_factory::set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + + string original_type_name; + m_inst_typename_alias_t orig_type_alias_per_inst; + + original_type_name = original_type.get_type_name(); + + if (!is_type_registered(original_type)) + uvm_report_warning("BDTYP",{"Cannot define alias of type '", + original_type_name,"' because it is not registered with the factory."}, UVM_NONE); + else begin + orig_type_alias_per_inst.alias_type_name = alias_type_name; + orig_type_alias_per_inst.full_inst_path = full_inst_path; + orig_type_alias_per_inst.orig.m_type_name = original_type_name; + orig_type_alias_per_inst.orig.m_type = original_type; + m_inst_aliases.push_back(orig_type_alias_per_inst); + end + +endfunction + + + + +// create_object_by_name +// --------------------- + +function uvm_object uvm_default_factory::create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + + uvm_object_wrapper wrapper; + string inst_path; + + if (parent_inst_path == "") + inst_path = name; + else if (name != "") + inst_path = {parent_inst_path,".",name}; + else + inst_path = parent_inst_path; + + m_override_info.delete(); + + wrapper = find_override_by_name(requested_type_name, inst_path); + + // if no override exists, try to use requested_type_name directly + if (wrapper==null) begin + wrapper = m_resolve_type_name_by_inst(requested_type_name,inst_path); + if(wrapper == null) begin + uvm_report_warning("BDTYP",{"Cannot create an object of type '", + requested_type_name,"' because it is not registered with the factory."}, UVM_NONE); + return null; + end + end + + return wrapper.create_object(name); + +endfunction + + +// create_object_by_type +// --------------------- + +function uvm_object uvm_default_factory::create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + + string full_inst_path; + + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + + m_override_info.delete(); + + requested_type = find_override_by_type(requested_type, full_inst_path); + + return requested_type.create_object(name); + +endfunction + +// is_type_name_registered +// --------------------- +function bit uvm_default_factory::is_type_name_registered (string type_name); + return (m_type_names.exists(type_name)); +endfunction + + +// is_type_registered +// --------------------- +function bit uvm_default_factory::is_type_registered (uvm_object_wrapper obj); + return (m_types.exists(obj)); +endfunction + + + +// create_component_by_name +// ------------------------ + +function uvm_component uvm_default_factory::create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + uvm_object_wrapper wrapper; + string inst_path; + + if (parent_inst_path == "") + inst_path = name; + else if (name != "") + inst_path = {parent_inst_path,".",name}; + else + inst_path = parent_inst_path; + + m_override_info.delete(); + + wrapper = find_override_by_name(requested_type_name, inst_path); + + // if no override exists, try to use requested_type_name directly + if (wrapper == null) begin + if(!m_type_names.exists(requested_type_name)) begin + uvm_report_warning("BDTYP",{"Cannot create a component of type '", + requested_type_name,"' because it is not registered with the factory."}, UVM_NONE); + return null; + end + wrapper = m_type_names[requested_type_name]; + end + + return wrapper.create_component(name, parent); + +endfunction + + +// create_component_by_type +// ------------------------ + +function uvm_component uvm_default_factory::create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + string full_inst_path; + + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + + m_override_info.delete(); + + requested_type = find_override_by_type(requested_type, full_inst_path); + + return requested_type.create_component(name, parent); + +endfunction + + + +// find_wrapper_by_name +// ------------ + +function uvm_object_wrapper uvm_default_factory::find_wrapper_by_name(string type_name); + + uvm_object_wrapper wrapper = m_resolve_type_name(type_name); + + if (wrapper != null) + return wrapper; + + uvm_report_warning("UnknownTypeName", {"find_wrapper_by_name: Type name '",type_name, + "' not registered with the factory."}, UVM_NONE); + +endfunction + + +// find_override_by_name +// --------------------- + +function uvm_object_wrapper uvm_default_factory::find_override_by_name (string requested_type_name, + string full_inst_path); + uvm_object_wrapper rtype; + uvm_factory_override lindex; + + rtype = m_resolve_type_name_by_inst(requested_type_name,full_inst_path); + + if(full_inst_path != "") + begin + foreach(m_inst_overrides[i]) begin + if(m_matches_inst_override(.override(m_inst_overrides[i]), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path))) begin + m_override_info.push_back(m_inst_overrides[i]); + if (lindex == null) begin + lindex = m_inst_overrides[i]; + if (!m_debug_pass) begin + break; + end + end + end + end + end + + if ((lindex == null) || m_debug_pass) begin + uvm_factory_override matched_overrides[$]; + // type override - exact match + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path), + .resolve_null_type_by_inst(1))) begin + matched_overrides.push_back(m_type_overrides[index]); + if ((lindex == null) || (lindex.replace == 0)) begin + lindex = m_type_overrides[index]; + // if override was done with replace == 1, then + // it has priority over overrides added before it. + // if override was done with replace == 0, then + // must continue to looked for an override added before + // it that would have higher priority + if (!m_debug_pass && lindex.replace) begin + break; + end + end + end + end + if(matched_overrides.size() != 0) begin + if (m_debug_pass) begin + m_override_info = {m_override_info,matched_overrides}; + end + else begin + m_override_info.push_back(matched_overrides[$]); + end + end + end + + if (lindex != null) begin + uvm_object_wrapper override = lindex.ovrd.m_type; + + lindex.used++; + if (m_debug_pass) begin + lindex.selected = 1; + end + + if(!m_matches_type_override(.override(lindex), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path), + .match_original_type(0), + .resolve_null_type_by_inst(1))) begin + if(override == null) begin + override = find_override_by_name(lindex.ovrd.m_type_name,full_inst_path); + end + else begin + override = find_override_by_type(override,full_inst_path); + end + end + else if(override == null) begin + override = m_resolve_type_name_by_inst(lindex.ovrd.m_type_name,full_inst_path); + end + if(override == null) begin + uvm_report_error("TYPNTF", {"Cannot resolve override for original type '", + lindex.orig.m_type_name,"' because the override type '", + lindex.ovrd.m_type_name, "' is not registered with the factory."}, UVM_NONE); + end + return override; + end + + // No override found + return null; + + +endfunction + + +// find_override_by_type +// --------------------- + +function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type, + string full_inst_path); + + uvm_object_wrapper override; + uvm_factory_override lindex; + + uvm_factory_queue_class qc; + + foreach (m_override_info[index]) begin + if ( //index != m_override_info.size()-1 && + m_override_info[index].orig.m_type == requested_type) begin + uvm_report_error("OVRDLOOP", "Recursive loop detected while finding override.", UVM_NONE); + m_override_info[index].used++; + if (!m_debug_pass) + debug_create_by_type (requested_type, full_inst_path); + + return requested_type; + end + end + if(full_inst_path != "") + begin + foreach(m_inst_overrides[i]) begin + if(m_matches_inst_override(.override(m_inst_overrides[i]), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path))) begin + m_override_info.push_back(m_inst_overrides[i]); + if (lindex == null) begin + lindex = m_inst_overrides[i]; + if (!m_debug_pass) begin + break; + end + end + end + end + end + + if ((lindex == null) || m_debug_pass) begin + uvm_factory_override matched_overrides[$]; + // type override - exact match + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path), + .resolve_null_type_by_inst(1))) begin + matched_overrides.push_back(m_type_overrides[index]); + if ((lindex == null) || (lindex.replace == 0)) begin + lindex = m_type_overrides[index]; + // if override was done with replace == 1, then + // it has priority over overrides added before it. + // if override was done with replace == 0, then + // must continue to looked for an override added before + // it that would have higher priority + if (!m_debug_pass && lindex.replace) begin + break; + end + end + end + end + if(matched_overrides.size() != 0) begin + if (m_debug_pass) begin + m_override_info = {m_override_info,matched_overrides}; + end + else begin + m_override_info.push_back(matched_overrides[$]); + end + end + end + + if (lindex != null) begin + uvm_object_wrapper override = lindex.ovrd.m_type; + + lindex.used++; + if (m_debug_pass) begin + lindex.selected = 1; + end + + if(!m_matches_type_override(.override(lindex), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path), + .match_original_type(0), + .resolve_null_type_by_inst(1))) begin + if(override == null) begin + override = find_override_by_name(lindex.ovrd.m_type_name,full_inst_path); + end + else begin + override = find_override_by_type(override,full_inst_path); + end + end + else if(override == null) begin + override = m_resolve_type_name_by_inst(lindex.ovrd.m_type_name,full_inst_path); + end + if(override == null) begin + uvm_report_error("TYPNTF", {"Cannot resolve override for original type '", + lindex.orig.m_type_name,"' because the override type '", + lindex.ovrd.m_type_name, "' is not registered with the factory."}, UVM_NONE); + end + return override; + end + + // No override found + + return requested_type; + +endfunction + + +// print +// ----- + +function void uvm_default_factory::print (int all_types=1); + + string key; + string qs[$]; + + qs.push_back("\n#### Factory Configuration (*)\n\n"); + + // print instance overrides + if(!m_type_overrides.size() && !m_inst_overrides.size()) + qs.push_back(" No instance or type overrides are registered with this factory\n"); + else begin + int max1,max2,max3; + string dash = "---------------------------------------------------------------------------------------------------"; + string space= " "; + + // print instance overrides + if(!m_inst_overrides.size()) + qs.push_back("No instance overrides are registered with this factory\n"); + else begin + foreach(m_inst_overrides[j]) begin + if (m_inst_overrides[j].orig.m_type_name.len() > max1) + max1=m_inst_overrides[j].orig.m_type_name.len(); + if (m_inst_overrides[j].full_inst_path.len() > max2) + max2=m_inst_overrides[j].full_inst_path.len(); + if (m_inst_overrides[j].ovrd.m_type_name.len() > max3) + max3=m_inst_overrides[j].ovrd.m_type_name.len(); + end + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + + qs.push_back("Instance Overrides:\n\n"); + qs.push_back($sformatf(" %0s%0s %0s%0s %0s%0s\n","Requested Type",space.substr(1,max1-14), + "Override Path", space.substr(1,max2-13), + "Override Type", space.substr(1,max3-13))); + qs.push_back($sformatf(" %0s %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2), + dash.substr(1,max3))); + + foreach(m_inst_overrides[j]) begin + qs.push_back($sformatf(" %0s%0s %0s%0s",m_inst_overrides[j].orig.m_type_name, + space.substr(1,max1-m_inst_overrides[j].orig.m_type_name.len()), + m_inst_overrides[j].full_inst_path, + space.substr(1,max2-m_inst_overrides[j].full_inst_path.len()))); + qs.push_back($sformatf(" %0s\n", m_inst_overrides[j].ovrd.m_type_name)); + end + end + + // print type overrides + if (!m_type_overrides.size()) + qs.push_back("\nNo type overrides are registered with this factory\n"); + else begin + // Resize for type overrides + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + + foreach (m_type_overrides[i]) begin + if (m_type_overrides[i].orig.m_type_name.len() > max1) + max1=m_type_overrides[i].orig.m_type_name.len(); + if (m_type_overrides[i].ovrd.m_type_name.len() > max2) + max2=m_type_overrides[i].ovrd.m_type_name.len(); + end + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + qs.push_back("\nType Overrides:\n\n"); + qs.push_back($sformatf(" %0s%0s %0s%0s\n","Requested Type",space.substr(1,max1-14), + "Override Type", space.substr(1,max2-13))); + qs.push_back($sformatf(" %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2))); + for (int index=m_type_overrides.size()-1; index>=0; index--) + qs.push_back($sformatf(" %0s%0s %0s\n", + m_type_overrides[index].orig.m_type_name, + space.substr(1,max1-m_type_overrides[index].orig.m_type_name.len()), + m_type_overrides[index].ovrd.m_type_name)); + end + end + + // print all registered types, if all_types >= 1 + if (all_types >= 1 && m_type_names.first(key)) begin + bit banner; + qs.push_back($sformatf("\nAll types registered with the factory: %0d total\n",m_types.num())); + do begin + // filter out uvm_ classes (if all_types<2) and non-types (lookup strings) + if (!(all_types < 2 && uvm_is_match("uvm_*", + m_type_names[key].get_type_name())) && + key == m_type_names[key].get_type_name()) begin + if (!banner) begin + qs.push_back(" Type Name\n"); + qs.push_back(" ---------\n"); + banner=1; + end + qs.push_back($sformatf(" %s\n", m_type_names[key].get_type_name())); + end + end while(m_type_names.next(key)); + end + + qs.push_back("(*) Types with no associated type name will be printed as \n\n####\n\n"); + + `uvm_info("UVM/FACTORY/PRINT",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE) +endfunction + + +// debug_create_by_name +// -------------------- + +function void uvm_default_factory::debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + m_debug_create(requested_type_name, null, parent_inst_path, name); +endfunction + + +// debug_create_by_type +// -------------------- + +function void uvm_default_factory::debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + m_debug_create("", requested_type, parent_inst_path, name); +endfunction + + +// m_debug_create +// -------------- + +function void uvm_default_factory::m_debug_create (string requested_type_name, + uvm_object_wrapper requested_type, + string parent_inst_path, + string name); + + string full_inst_path; + uvm_object_wrapper result; + + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + + m_override_info.delete(); + + if (requested_type == null) begin + if (!m_type_names.exists(requested_type_name) && + !m_lookup_strs.exists(requested_type_name)) begin + uvm_report_warning("Factory Warning", {"The factory does not recognize '", + requested_type_name,"' as a registered type."}, UVM_NONE); + return; + end + m_debug_pass = 1; + + result = find_override_by_name(requested_type_name,full_inst_path); + end + else begin + m_debug_pass = 1; + if (!m_types.exists(requested_type)) + register(requested_type); + result = find_override_by_type(requested_type,full_inst_path); + if (requested_type_name == "") + requested_type_name = requested_type.get_type_name(); + end + + m_debug_display(requested_type_name, result, full_inst_path); + m_debug_pass = 0; + + foreach (m_override_info[index]) + m_override_info[index].selected = 0; + +endfunction + + +// m_debug_display +// --------------- + +function void uvm_default_factory::m_debug_display (string requested_type_name, + uvm_object_wrapper result, + string full_inst_path); + + int max1,max2,max3; + string dash = "---------------------------------------------------------------------------------------------------"; + string space= " "; + string qs[$]; + + qs.push_back("\n#### Factory Override Information (*)\n\n"); + qs.push_back( + $sformatf("Given a request for an object of type '%s' with an instance\npath of '%s' the factory encountered\n\n", + requested_type_name,full_inst_path)); + + if (m_override_info.size() == 0) + qs.push_back("no relevant overrides.\n\n"); + else begin + + qs.push_back("the following relevant overrides. An 'x' next to a match indicates a\nmatch that was ignored.\n\n"); + + foreach (m_override_info[i]) begin + if (m_override_info[i].orig.m_type_name.len() > max1) + max1=m_override_info[i].orig.m_type_name.len(); + if (m_override_info[i].full_inst_path.len() > max2) + max2=m_override_info[i].full_inst_path.len(); + if (m_override_info[i].ovrd.m_type_name.len() > max3) + max3=m_override_info[i].ovrd.m_type_name.len(); + end + + if (max1 < 13) max1 = 13; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + + qs.push_back($sformatf("Original Type%0s Instance Path%0s Override Type%0s\n", + space.substr(1,max1-13),space.substr(1,max2-13),space.substr(1,max3-13))); + + qs.push_back($sformatf(" %0s %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2), + dash.substr(1,max3))); + + foreach (m_override_info[i]) begin + qs.push_back($sformatf("%s%0s%0s\n", + m_override_info[i].selected ? " " : "x ", + m_override_info[i].orig.m_type_name, + space.substr(1,max1-m_override_info[i].orig.m_type_name.len()))); + qs.push_back($sformatf(" %0s%0s", m_override_info[i].full_inst_path, + space.substr(1,max2-m_override_info[i].full_inst_path.len()))); + qs.push_back($sformatf(" %0s%0s", m_override_info[i].ovrd.m_type_name, + space.substr(1,max3-m_override_info[i].ovrd.m_type_name.len()))); + if (m_override_info[i].full_inst_path == "*") + qs.push_back(" "); + else + qs.push_back("\n"); + end + qs.push_back("\n"); + end + + + qs.push_back("Result:\n\n"); + qs.push_back($sformatf(" The factory will produce an object of type '%0s'\n", + result == null ? requested_type_name : result.get_type_name())); + + qs.push_back("\n(*) Types with no associated type name will be printed as \n\n####\n\n"); + + `uvm_info("UVM/FACTORY/DUMP",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE) +endfunction + + +// m_resolve_type_name +// -------------------- + +function uvm_object_wrapper uvm_default_factory::m_resolve_type_name(string requested_type_name); + uvm_object_wrapper wrapper=null; + if(m_type_names.exists(requested_type_name)) + wrapper = m_type_names[requested_type_name]; + + return wrapper; +endfunction + +// m_resolve_type_name_by_inst +// -------------------- + +function uvm_object_wrapper uvm_default_factory::m_resolve_type_name_by_inst(string requested_type_name, + string full_inst_path); + uvm_object_wrapper wrapper=null; + m_inst_typename_alias_t type_alias_inst[$]; + type_alias_inst = m_inst_aliases.find(i) with ((i.alias_type_name == requested_type_name) && uvm_is_match(i.full_inst_path,full_inst_path)); + if (type_alias_inst.size() > 0) begin + wrapper = type_alias_inst[0].orig.m_type; + end + else begin + wrapper = m_resolve_type_name(requested_type_name); + end + + return wrapper; +endfunction + +// m_matches_type_pair +// -------------------- + +function bit uvm_default_factory::m_matches_type_pair(m_uvm_factory_type_pair_t match_type_pair, + uvm_object_wrapper requested_type, + string requested_type_name); + return ((match_type_pair.m_type != null) && + (match_type_pair.m_type == requested_type) || + (match_type_pair.m_type_name != "" && + match_type_pair.m_type_name != "" && + match_type_pair.m_type_name == requested_type_name)); +endfunction + +// m_matches_inst_override +// -------------------- + +function bit uvm_default_factory::m_matches_inst_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path=""); + m_uvm_factory_type_pair_t match_type_pair = override.orig ; + if(match_type_pair.m_type == null) begin + match_type_pair.m_type = m_resolve_type_name_by_inst(match_type_pair.m_type_name, full_inst_path); + end + if (m_matches_type_pair(.match_type_pair(match_type_pair), + .requested_type(requested_type), + .requested_type_name(requested_type_name))) begin + if(override.has_wildcard) begin + return (override.full_inst_path == "*" || + uvm_is_match(override.full_inst_path,full_inst_path)); + end + else begin + return (override.full_inst_path == full_inst_path); + end + end + return 0; +endfunction + +// m_matches_type_override +// -------------------- + +function bit uvm_default_factory::m_matches_type_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path="", + bit match_original_type = 1, + bit resolve_null_type_by_inst=0); + m_uvm_factory_type_pair_t match_type_pair = match_original_type ? override.orig : override.ovrd; + if(match_type_pair.m_type == null) begin + if(resolve_null_type_by_inst) begin + match_type_pair.m_type = m_resolve_type_name_by_inst(match_type_pair.m_type_name,full_inst_path); + end + else begin + match_type_pair.m_type = m_resolve_type_name(match_type_pair.m_type_name); + end + end + return m_matches_type_pair(.match_type_pair(match_type_pair), + .requested_type(requested_type), + .requested_type_name(requested_type_name)); +endfunction diff --git a/test_regress/t/t_uvm/base/uvm_field_op.svh b/test_regress/t/t_uvm/base/uvm_field_op.svh new file mode 100644 index 0000000000..9a2f60ff3a --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_field_op.svh @@ -0,0 +1,180 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Synopsys, Inc. +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 NVIDIA Corporation +// Copyright 2018 Cisco Systems, 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 - uvm_field_op +// +// uvm_field_op is the UVM class for describing all operations supported by the do_execute_op function +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 5.3.13.2.1 +class uvm_field_op extends uvm_object; + + // @uvm-ieee 1800.2-2017 auto 5.3.4.5 + // @uvm-ieee 1800.2-2017 auto 5.3.4.6 + // @uvm-ieee 1800.2-2017 auto 5.3.4.7 + // @uvm-ieee 1800.2-2017 auto 5.3.5.1 + `uvm_object_utils(uvm_field_op) + + local uvm_policy m_policy; + local bit m_user_hook; + local uvm_object m_object; + // Bit m_is_set is set when the set() method is called and acts + // like a state variable. It is cleared when flush is called. + local bit m_is_set; + local uvm_field_flag_t m_op_type; + + + // Function -- new + // + // Creates a policy with the specified instance name. If name is not provided, then the policy instance is + // unnamed. + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.3 + // @uvm-ieee 1800.2-2017 auto 5.3.2 + function new (string name=""); + super.new(name); + m_is_set = 1'b0; + m_user_hook = 1'b1; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.4 + virtual function void set( uvm_field_flag_t op_type, uvm_policy policy = null, uvm_object rhs = null); + string matching_ops[$]; + if (op_type & UVM_COPY) + matching_ops.push_back("UVM_COPY"); + if (op_type & UVM_COMPARE) + matching_ops.push_back("UVM_COMPARE"); + if (op_type & UVM_PRINT) + matching_ops.push_back("UVM_PRINT"); + if (op_type & UVM_RECORD) + matching_ops.push_back("UVM_RECORD"); + if (op_type & UVM_PACK) + matching_ops.push_back("UVM_PACK"); + if (op_type & UVM_UNPACK) + matching_ops.push_back("UVM_UNPACK"); + if (op_type & UVM_SET) + matching_ops.push_back("UVM_SET"); + + if (matching_ops.size() > 1) begin + string msg_queue[$]; + msg_queue.push_back("("); + foreach (matching_ops[i]) begin + msg_queue.push_back(matching_ops[i]); + if (i != matching_ops.size() - 1) + msg_queue.push_back(","); + end + msg_queue.push_back(")"); + `uvm_error("UVM/FIELD_OP/SET_BAD_OP_TYPE", {"set() was passed op_type matching multiple operations: ", `UVM_STRING_QUEUE_STREAMING_PACK(msg_queue)}) + end + + if(m_is_set == 0) begin + m_op_type = op_type; + m_policy = policy; + m_object = rhs; + m_is_set = 1'b1; + end + else + `uvm_error("UVM/FIELD_OP/SET","Attempting to set values in policy without flushing") + endfunction + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.5 + virtual function string get_op_name(); + case(m_op_type) + UVM_COPY : return "copy"; + UVM_COMPARE : return "compare"; + UVM_PRINT : return "print"; + UVM_RECORD : return "record"; + UVM_PACK : return "pack"; + UVM_UNPACK : return "unpack"; + UVM_SET : return "set"; + default: return ""; + endcase + endfunction + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.6 + virtual function uvm_field_flag_t get_op_type(); + if(m_is_set == 1'b1) + return m_op_type; + else + `uvm_error("UVM/FIELD_OP/GET_OP_TYPE","Calling get_op_type() before calling set() is not allowed") + endfunction + + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.7 + virtual function uvm_policy get_policy(); + if(m_is_set == 1'b1) + return m_policy; + else + `uvm_error("UVM/FIELD_OP/GET_POLICY","Attempting to call get_policy() before calling set() is not allowed") + endfunction + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.8 + virtual function uvm_object get_rhs(); + if(m_is_set == 1'b1) + return m_object; + else + `uvm_error("UVM/FIELD_OP/GET_RHS","Calling get_rhs() before calling set() is not allowed") + endfunction + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.9 + function bit user_hook_enabled(); + if(m_is_set == 1'b1) + return m_user_hook; + else + `uvm_error("UVM/FIELD_OP/GET_USER_HOOK","Attempting to get_user_hook before calling set() is not allowed") + endfunction + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.10 + function void disable_user_hook(); + m_user_hook = 1'b0; + endfunction + + static uvm_field_op m_recycled_op[$] ; + + // @uvm-ieee 1800.2-2017 auto 5.3.13.2.11 + virtual function void flush(); + m_policy = null; + m_object = null; + m_user_hook = 1'b1; + m_is_set = 0; + endfunction + + // API for reusing uvm_field_op instances. Implementation + // artifact, should not be used directly by the user. + function void m_recycle(); + this.flush(); + m_recycled_op.push_back(this); + endfunction : m_recycle + + static function uvm_field_op m_get_available_op() ; + uvm_field_op field_op ; + if (m_recycled_op.size() > 0) field_op = m_recycled_op.pop_back() ; +`ifdef VERILATOR + else field_op = uvm_field_op::type_id_create("field_op"); +`else + else field_op = uvm_field_op::type_id::create("field_op"); +`endif + return field_op ; + endfunction +endclass diff --git a/test_regress/t/t_uvm/base/uvm_globals.svh b/test_regress/t/t_uvm/base/uvm_globals.svh new file mode 100644 index 0000000000..48a4731f82 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_globals.svh @@ -0,0 +1,510 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +typedef class uvm_root; +typedef class uvm_report_object; +typedef class uvm_report_message; + +// Title -- NODOCS -- Globals + +//------------------------------------------------------------------------------ +// +// Group -- NODOCS -- Simulation Control +// +//------------------------------------------------------------------------------ + +// Task -- NODOCS -- run_test +// +// Convenience function for uvm_top.run_test(). See for more +// information. + +// @uvm-ieee 1800.2-2017 auto F.3.1.2 +task run_test (string test_name=""); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.run_test(test_name); +endtask + +//---------------------------------------------------------------------------- +// +// Group -- NODOCS -- Reporting +// +//---------------------------------------------------------------------------- + + + +// @uvm-ieee 1800.2-2017 auto F.3.2.1 +function uvm_report_object uvm_get_report_object(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + return top; +endfunction + + +// Function -- NODOCS -- uvm_report_enabled +// +// Returns 1 if the configured verbosity in ~uvm_top~ for this +// severity/id is greater than or equal to ~verbosity~ else returns 0. +// +// See also . +// +// Static methods of an extension of uvm_report_object, e.g. uvm_component-based +// objects, cannot call ~uvm_report_enabled~ because the call will resolve to +// the , which is non-static. +// Static methods cannot call non-static methods of the same class. + +// @uvm-ieee 1800.2-2017 auto F.3.2.2 +function int uvm_report_enabled (int verbosity, + uvm_severity severity=UVM_INFO, string id=""); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + return top.uvm_report_enabled(verbosity,severity,id); +endfunction + +// Function -- NODOCS -- uvm_report + +// @uvm-ieee 1800.2-2017 auto F.3.2.3 +function void uvm_report( uvm_severity severity, + string id, + string message, + int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : + (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report(severity, id, message, verbosity, filename, line, context_name, report_enabled_checked); +endfunction + +// Undocumented DPI available version of uvm_report +`ifndef VERILATOR +export "DPI-C" function m__uvm_report_dpi; +`endif +function void m__uvm_report_dpi(int severity, + string id, + string message, + int verbosity, + string filename, + int line); + uvm_report(uvm_severity'(severity), id, message, verbosity, filename, line); +endfunction : m__uvm_report_dpi + +// Function -- NODOCS -- uvm_report_info + +// @uvm-ieee 1800.2-2017 auto F.3.2.3 +function void uvm_report_info(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_info(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction + + +// Function -- NODOCS -- uvm_report_warning + +// @uvm-ieee 1800.2-2017 auto F.3.2.3 +function void uvm_report_warning(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_warning(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction + + +// Function -- NODOCS -- uvm_report_error + +// @uvm-ieee 1800.2-2017 auto F.3.2.3 +function void uvm_report_error(string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_error(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction + + +// Function -- NODOCS -- uvm_report_fatal +// +// These methods, defined in package scope, are convenience functions that +// delegate to the corresponding component methods in ~uvm_top~. They can be +// used in module-based code to use the same reporting mechanism as class-based +// components. See for details on the reporting mechanism. +// +// *Note:* Verbosity is ignored for warnings, errors, and fatals to ensure users +// do not inadvertently filter them out. It remains in the methods for backward +// compatibility. + +// @uvm-ieee 1800.2-2017 auto F.3.2.3 +function void uvm_report_fatal(string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_fatal(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction + + +// Function -- NODOCS -- uvm_process_report_message +// +// This method, defined in package scope, is a convenience function that +// delegate to the corresponding component method in ~uvm_top~. It can be +// used in module-based code to use the same reporting mechanism as class-based +// components. See for details on the reporting mechanism. + +// @uvm-ieee 1800.2-2017 auto F.3.2.3 +function void uvm_process_report_message(uvm_report_message report_message); + uvm_root top; + uvm_coreservice_t cs; + process p; + p = process::self(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_process_report_message(report_message); +endfunction + + +// TODO merge with uvm_enum_wrapper#(uvm_severity) +function bit uvm_string_to_severity (string sev_str, output uvm_severity sev); + case (sev_str) + "UVM_INFO": sev = UVM_INFO; + "UVM_WARNING": sev = UVM_WARNING; + "UVM_ERROR": sev = UVM_ERROR; + "UVM_FATAL": sev = UVM_FATAL; + default: return 0; + endcase + return 1; +endfunction + + +function automatic bit uvm_string_to_action (string action_str, output uvm_action action); + string actions[$]; + uvm_split_string(action_str,"|",actions); + uvm_string_to_action = 1; + action = 0; + foreach(actions[i]) begin + case (actions[i]) + "UVM_NO_ACTION": action |= UVM_NO_ACTION; + "UVM_DISPLAY": action |= UVM_DISPLAY; + "UVM_LOG": action |= UVM_LOG; + "UVM_COUNT": action |= UVM_COUNT; + "UVM_EXIT": action |= UVM_EXIT; + "UVM_CALL_HOOK": action |= UVM_CALL_HOOK; + "UVM_STOP": action |= UVM_STOP; + "UVM_RM_RECORD": action |= UVM_RM_RECORD; + default: uvm_string_to_action = 0; + endcase + end +endfunction + + +//---------------------------------------------------------------------------- +// +// Group: Miscellaneous +// +// The library implements the following public API at the package level beyond +// what is documented in IEEE 1800.2. +//---------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto F.3.3.1 +function bit uvm_is_match (string expr, string str); + string s; + s = uvm_glob_to_re(expr); + return (uvm_re_match(s, str) == 0); +endfunction + + +parameter UVM_LINE_WIDTH = `UVM_LINE_WIDTH; +parameter UVM_NUM_LINES = `UVM_NUM_LINES; +parameter UVM_SMALL_STRING = UVM_LINE_WIDTH*8-1; +parameter UVM_LARGE_STRING = UVM_LINE_WIDTH*UVM_NUM_LINES*8-1; + + +//---------------------------------------------------------------------------- +// +// Function -- NODOCS -- uvm_string_to_bits +// +// Converts an input string to its bit-vector equivalent. Max bit-vector +// length is approximately 14000 characters. +//---------------------------------------------------------------------------- + +function logic[UVM_LARGE_STRING:0] uvm_string_to_bits(string str); + $swrite(uvm_string_to_bits, "%0s", str); +endfunction + +// @uvm-ieee 1800.2-2017 auto F.3.1.1 +function uvm_core_state get_core_state(); + return m_uvm_core_state; +endfunction + +// Function: uvm_init +// Implementation of uvm_init, as defined in section +// F.3.1.3 in 1800.2-2017. +// +// *Note:* The LRM states that subsequent calls to after +// the first are silently ignored, however there are scenarios wherein +// the implementation breaks this requirement. +// +// If the core state (see ) is ~UVM_CORE_PRE_INIT~ when , +// is called, then the library can not determine the appropriate core service. As +// such, the default core service will be constructed and a fatal message +// shall be generated. +// +// If the core state is past ~UVM_CORE_PRE_INIT~, and ~cs~ is a non-null core +// service instance different than the value passed to the first call, +// then the library will generate a warning message to alert the user that this +// call to is being ignored. +// +// @uvm-contrib This API represents a potential contribution to IEEE 1800.2 + +// @uvm-ieee 1800.2-2017 auto F.3.1.3 +function void uvm_init(uvm_coreservice_t cs=null); + uvm_default_coreservice_t dcs; + + if(get_core_state()!=UVM_CORE_UNINITIALIZED) begin + if (get_core_state() == UVM_CORE_PRE_INIT) begin + // If we're in this state, something very strange has happened. + // We've called uvm_init, and it is actively assigning the + // core service, but the core service isn't actually set yet. + // This means that either the library messed something up, or + // we have a race occurring between two threads. Either way, + // this is non-recoverable. We're going to setup using the default + // core service, and immediately fatal out. + dcs = new(); + uvm_coreservice_t::set(dcs); + `uvm_fatal("UVM/INIT/MULTI", "Non-recoverable race during uvm_init") + end + else begin + // After PRE_INIT, we can check to see if this is worth reporting + // as a warning. We only report it if the value for ~cs~ is _not_ + // the current core service, and ~cs~ is not null. + uvm_coreservice_t actual; + actual = uvm_coreservice_t::get(); + if ((cs != actual) && (cs != null)) + `uvm_warning("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!") + end + return; + end + m_uvm_core_state=UVM_CORE_PRE_INIT; + + // We control the implementation of uvm_default_coreservice_t::new + // and uvm_coreservice_t::set (which is undocumented). As such, + // we guarantee that they will not trigger any calls to uvm_init. + if(cs == null) begin + dcs = new(); + cs = dcs; + end + uvm_coreservice_t::set(cs); + + // After this point, it should be safe to query the + // corservice for anything. We're not done with + // initialization, but the coreservice (and the + // various elements it controls) are 'stable'. + // + // Note that a user could have something silly + // in their own space, like a specialization of + // uvm_root with a constructor that relies on a + // specialization of uvm_factory with a + // constructor that relies on the specialized + // root being constructed... but there's not + // really anything that can be done about that. + m_uvm_core_state=UVM_CORE_INITIALIZING; + + foreach(uvm_deferred_init[idx]) begin + uvm_deferred_init[idx].initialize(); + end + + uvm_deferred_init.delete(); + + begin + uvm_root top; + top = uvm_root::get(); + // These next calls were moved to uvm_init from uvm_root, + // because they could emit messages, resulting in the + // report server being queried, which causes uvm_init. + top.report_header(); + top.m_check_uvm_field_flag_size(); + // This sets up the global verbosity. Other command line args may + // change individual component verbosity. + top.m_check_verbosity(); + end + + m_uvm_core_state=UVM_CORE_INITIALIZED; +endfunction + +//---------------------------------------------------------------------------- +// +// Function -- NODOCS -- uvm_bits_to_string +// +// Converts an input bit-vector to its string equivalent. Max bit-vector +// length is approximately 14000 characters. +//---------------------------------------------------------------------------- + +function string uvm_bits_to_string(logic [UVM_LARGE_STRING:0] str); + $swrite(uvm_bits_to_string, "%0s", str); +endfunction + + +//---------------------------------------------------------------------------- +// +// Task: uvm_wait_for_nba_region +// +// This task will block until SystemVerilog's NBA region (or Re-NBA region if +// called from a program context). The purpose is to continue the calling +// process only after allowing other processes any number of delta cycles (#0) +// to settle out. +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 +//---------------------------------------------------------------------------- + +task uvm_wait_for_nba_region; + + int nba; + int next_nba; + + //If `included directly in a program block, can't use a non-blocking assign, + //but it isn't needed since program blocks are in a separate region. +`ifndef UVM_NO_WAIT_FOR_NBA + next_nba++; + nba <= next_nba; + @(nba); +`else + repeat(`UVM_POUND_ZERO_COUNT) #0; +`endif + + +endtask + + +//---------------------------------------------------------------------------- +// +// Function -- NODOCS -- uvm_split_string +// +// Returns a queue of strings, ~values~, that is the result of the ~str~ split +// based on the ~sep~. For example: +// +//| uvm_split_string("1,on,false", ",", splits); +// +// Results in the 'splits' queue containing the three elements: 1, on and +// false. +//---------------------------------------------------------------------------- + +function automatic void uvm_split_string (string str, byte sep, ref string values[$]); + int s = 0, e = 0; + values.delete(); + while(e < str.len()) begin + for(s=e; e +// method which is the logical inverse of the System Verilog ~name~ +// method which is built into all enumerations. + +// @uvm-ieee 1800.2-2017 auto F.3.4.1 +class uvm_enum_wrapper#(type T=uvm_active_passive_enum); + + protected static T map[string]; + + + // @uvm-ieee 1800.2-2017 auto F.3.4.2 + static function bit from_name(string name, ref T value); + if (map.size() == 0) + m_init_map(); + + if (map.exists(name)) begin + value = map[name]; + return 1; + end + else begin + return 0; + end + endfunction : from_name + + // Function- m_init_map + // Initializes the name map, only needs to be performed once + protected static function void m_init_map(); + T e = e.first(); + do + begin + map[e.name()] = e; + e = e.next(); + end + while (e != e.first()); + endfunction : m_init_map + + // Function- new + // Prevents accidental instantiations + protected function new(); + endfunction : new + +endclass : uvm_enum_wrapper diff --git a/test_regress/t/t_uvm/base/uvm_heartbeat.svh b/test_regress/t/t_uvm/base/uvm_heartbeat.svh new file mode 100644 index 0000000000..0c4bb2c7e4 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_heartbeat.svh @@ -0,0 +1,349 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 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_SVH + +typedef 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 /* @uvm-ieee 1800.2-2017 auto D.4.2*/ ; + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- 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; +// @uvm-ieee 1800.2-2017 auto 10.6.1 +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 -- NODOCS -- 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); + //| ... + //| endclass + + // @uvm-ieee 1800.2-2017 auto 10.6.2.1 + function 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 -- NODOCS -- 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. + + // @uvm-ieee 1800.2-2017 auto 10.6.2.2 + 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 -- NODOCS -- 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 the monitor and then 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 . + + // @uvm-ieee 1800.2-2017 auto 10.6.2.3 + function void set_heartbeat (uvm_event#(uvm_object) e, ref uvm_component comps[$]); + uvm_object c; + foreach(comps[i]) begin + c = 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; + end + if(e==null && m_event==null) return; + start(e); + endfunction + + // Function -- NODOCS -- 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. + + // @uvm-ieee 1800.2-2017 auto 10.6.2.4 + 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 -- NODOCS -- 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). + + // @uvm-ieee 1800.2-2017 auto 10.6.2.5 + 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 -- NODOCS -- 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. + + // @uvm-ieee 1800.2-2017 auto 10.6.2.6 + function void start (uvm_event#(uvm_object) e=null); + if(m_event == null && e == null) begin + m_cntxt.uvm_report_warning("NOEVNT", { "start() was called for: ", + get_name(), " with a null trigger and no currently set trigger" }, + UVM_NONE); + return; + end + if((m_event != null) && (e != m_event) && m_started) begin + m_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; + end + if(e != null) m_event = e; + m_enable_cb(); + m_start_hb_process(); + endfunction + + // Function -- NODOCS -- stop + // + // Stops the heartbeat monitor. Current state information is reset so + // that if is called again the process will wait for the first + // event trigger to start the monitoring. + + // @uvm-ieee 1800.2-2017 auto 10.6.2.7 + function void stop (); + m_started = 0; + ->m_stop_event; + m_disable_cb(); + endfunction + + function void m_start_hb_process(); + if(m_started) return; + m_started = 1; + fork + m_hb_process; + join_none + endfunction + + protected 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; + endfunction + + function void m_disable_cb; + void'(m_cb.callback_mode(0)); + endfunction + + task m_hb_process; + uvm_object obj; + bit triggered; + time last_trigger=0; + fork + begin + // 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) begin + m_event.wait_trigger(); + if(triggered) begin + case (m_mode) + UVM_ALL_ACTIVE: + begin + foreach(m_cb.cnt[idx]) begin + obj = idx; + if(!m_cb.cnt[obj]) begin + m_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); + end + end + end + UVM_ANY_ACTIVE: + begin + if(m_cb.cnt.num() && !m_cb.objects_triggered()) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + s={s,"\n ",obj.get_full_name()}; + end + m_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); + end + end + UVM_ONE_ACTIVE: + begin + if(m_cb.objects_triggered() > 1) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + if(m_cb.cnt[obj]) $swrite(s,"%s\n %s (updated: %0t)", + s, obj.get_full_name(), m_cb.last_trigger[obj]); + end + m_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); + end + if(m_cb.cnt.num() && !m_cb.objects_triggered()) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + s={s,"\n ",obj.get_full_name()}; + end + m_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); + end + end + endcase + end + m_cb.reset_counts(); + last_trigger = $realtime; + triggered = 1; + end + end + @(m_stop_event); + join_any + disable fork; + endtask +endclass + + +class 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; + else + this.target = cs.get_root(); + endfunction + + virtual function void raised (uvm_objection objection, + uvm_object obj, + uvm_object source_obj, + string description, + int count); + if(obj == target) begin + if(!cnt.exists(source_obj)) + cnt[source_obj] = 0; + cnt[source_obj] = cnt[source_obj]+1; + last_trigger[source_obj] = $realtime; + end + endfunction + + virtual function void dropped (uvm_objection objection, + uvm_object obj, + uvm_object source_obj, + string description, + int count); + raised(objection,obj,source_obj,description,count); + endfunction + + function void reset_counts; + foreach(cnt[i]) cnt[i] = 0; + endfunction + + function int objects_triggered; + objects_triggered = 0; + foreach(cnt[i]) + if (cnt[i] != 0) + objects_triggered++; + endfunction + +endclass + +`endif diff --git a/test_regress/t/t_uvm/base/uvm_links.svh b/test_regress/t/t_uvm/base/uvm_links.svh new file mode 100644 index 0000000000..84bed1b6ae --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_links.svh @@ -0,0 +1,322 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 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. +//----------------------------------------------------------------------------- + +// File -- NODOCS -- UVM Links +// +// The class, and its extensions, are provided as a mechanism +// to allow for compile-time safety when trying to establish links between +// records within a . +// +// + + +// @uvm-ieee 1800.2-2017 auto 7.3.1.1 +virtual class uvm_link_base extends uvm_object; + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.2 + function new(string name="unnamed-uvm_link_base"); + super.new(name); + endfunction : new + + // Group -- NODOCS -- Accessors + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.3.2 + function void set_lhs(uvm_object lhs); + do_set_lhs(lhs); + endfunction : set_lhs + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.3.1 + function uvm_object get_lhs(); + return do_get_lhs(); + endfunction : get_lhs + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.3.4 + function void set_rhs(uvm_object rhs); + do_set_rhs(rhs); + endfunction : set_rhs + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.3.3 + function uvm_object get_rhs(); + return do_get_rhs(); + endfunction : get_rhs + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.3.5 + function void set(uvm_object lhs, rhs); + do_set_lhs(lhs); + do_set_rhs(rhs); + endfunction : set + + // Group -- NODOCS -- Implementation Callbacks + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.4.2 + pure virtual function void do_set_lhs(uvm_object lhs); + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.4.1 + pure virtual function uvm_object do_get_lhs(); + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.4.4 + pure virtual function void do_set_rhs(uvm_object rhs); + + + // @uvm-ieee 1800.2-2017 auto 7.3.1.4.3 + pure virtual function uvm_object do_get_rhs(); + +endclass : uvm_link_base + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_parent_child_link +// +// The ~uvm_parent_child_link~ is used to represent a Parent/Child relationship +// between two objects. +// + +// @uvm-ieee 1800.2-2017 auto 7.3.2.1 +class uvm_parent_child_link extends uvm_link_base; + + // Variable- m_lhs,m_rhs + // Implementation details + local uvm_object m_lhs; + local uvm_object m_rhs; + + // Object utils + `uvm_object_utils(uvm_parent_child_link) + + + // @uvm-ieee 1800.2-2017 auto 7.3.2.2.1 + function new(string name="unnamed-uvm_parent_child_link"); + super.new(name); + endfunction : new + + + // @uvm-ieee 1800.2-2017 auto 7.3.2.2.2 + static function uvm_parent_child_link get_link(uvm_object lhs, + uvm_object rhs, + string name="pc_link"); + process p_; + string s_; + + p_ = process::self(); + if (p_ != null) + s_ = p_.get_randstate(); + + get_link = new(name); + + if (p_ != null) + p_.set_randstate(s_); + + get_link.set(lhs, rhs); + endfunction : get_link + + // Group -- NODOCS -- Implementation Callbacks + + // Function -- NODOCS -- do_set_lhs + // Sets the left-hand-side (Parent) + // + virtual function void do_set_lhs(uvm_object lhs); + m_lhs = lhs; + endfunction : do_set_lhs + + // Function -- NODOCS -- do_get_lhs + // Retrieves the left-hand-side (Parent) + // + virtual function uvm_object do_get_lhs(); + return m_lhs; + endfunction : do_get_lhs + + // Function -- NODOCS -- do_set_rhs + // Sets the right-hand-side (Child) + // + virtual function void do_set_rhs(uvm_object rhs); + m_rhs = rhs; + endfunction : do_set_rhs + + // Function -- NODOCS -- do_get_rhs + // Retrieves the right-hand-side (Child) + // + virtual function uvm_object do_get_rhs(); + return m_rhs; + endfunction : do_get_rhs + +endclass : uvm_parent_child_link + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_cause_effect_link +// +// The ~uvm_cause_effect_link~ is used to represent a Cause/Effect relationship +// between two objects. +// + +// @uvm-ieee 1800.2-2017 auto 7.3.3.1 +class uvm_cause_effect_link extends uvm_link_base; + + // Variable- m_lhs,m_rhs + // Implementation details + local uvm_object m_lhs; + local uvm_object m_rhs; + + // Object utils + `uvm_object_utils(uvm_cause_effect_link) + + + // @uvm-ieee 1800.2-2017 auto 7.3.3.2.1 + function new(string name="unnamed-uvm_cause_effect_link"); + super.new(name); + endfunction : new + + + // @uvm-ieee 1800.2-2017 auto 7.3.3.2.2 + static function uvm_cause_effect_link get_link(uvm_object lhs, + uvm_object rhs, + string name="ce_link"); + process p_; + string s_; + p_ = process::self(); + if (p_ != null) + s_ = p_.get_randstate(); + + get_link = new(name); + + if (p_ != null) + p_.set_randstate(s_); + + get_link.set(lhs, rhs); + endfunction : get_link + + // Group -- NODOCS -- Implementation Callbacks + + // Function -- NODOCS -- do_set_lhs + // Sets the left-hand-side (Cause) + // + virtual function void do_set_lhs(uvm_object lhs); + m_lhs = lhs; + endfunction : do_set_lhs + + // Function -- NODOCS -- do_get_lhs + // Retrieves the left-hand-side (Cause) + // + virtual function uvm_object do_get_lhs(); + return m_lhs; + endfunction : do_get_lhs + + // Function -- NODOCS -- do_set_rhs + // Sets the right-hand-side (Effect) + // + virtual function void do_set_rhs(uvm_object rhs); + m_rhs = rhs; + endfunction : do_set_rhs + + // Function -- NODOCS -- do_get_rhs + // Retrieves the right-hand-side (Effect) + // + virtual function uvm_object do_get_rhs(); + return m_rhs; + endfunction : do_get_rhs + +endclass : uvm_cause_effect_link + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_related_link +// +// The ~uvm_related_link~ is used to represent a generic "is related" link +// between two objects. +// + +// @uvm-ieee 1800.2-2017 auto 7.3.4.1 +class uvm_related_link extends uvm_link_base; + + // Variable- m_lhs,m_rhs + // Implementation details + local uvm_object m_lhs; + local uvm_object m_rhs; + + // Object utils + `uvm_object_utils(uvm_related_link) + + + // @uvm-ieee 1800.2-2017 auto 7.3.4.2.1 + function new(string name="unnamed-uvm_related_link"); + super.new(name); + endfunction : new + + + // @uvm-ieee 1800.2-2017 auto 7.3.4.2.2 + static function uvm_related_link get_link(uvm_object lhs, + uvm_object rhs, + string name="ce_link"); + process p_; + string s_; + p_ = process::self(); + if (p_ != null) + s_ = p_.get_randstate(); + + get_link = new(name); + + if (p_ != null) + p_.set_randstate(s_); + + get_link.set(lhs, rhs); + endfunction : get_link + + // Group -- NODOCS -- Implementation Callbacks + + // Function -- NODOCS -- do_set_lhs + // Sets the left-hand-side + // + virtual function void do_set_lhs(uvm_object lhs); + m_lhs = lhs; + endfunction : do_set_lhs + + // Function -- NODOCS -- do_get_lhs + // Retrieves the left-hand-side + // + virtual function uvm_object do_get_lhs(); + return m_lhs; + endfunction : do_get_lhs + + // Function -- NODOCS -- do_set_rhs + // Sets the right-hand-side + // + virtual function void do_set_rhs(uvm_object rhs); + m_rhs = rhs; + endfunction : do_set_rhs + + // Function -- NODOCS -- do_get_rhs + // Retrieves the right-hand-side + // + virtual function uvm_object do_get_rhs(); + return m_rhs; + endfunction : do_get_rhs + +endclass : uvm_related_link diff --git a/test_regress/t/t_uvm/base/uvm_misc.svh b/test_regress/t/t_uvm/base/uvm_misc.svh new file mode 100644 index 0000000000..33a048e305 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_misc.svh @@ -0,0 +1,512 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2018 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2017 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013 Verilab +// Copyright 2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014-2018 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +// File -- NODOCS -- Miscellaneous Structures + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_void +// +// The ~uvm_void~ class is the base class for all UVM classes. It is an abstract +// class with no data members or functions. It allows for generic containers of +// objects to be created, similar to a void pointer in the C programming +// language. User classes derived directly from ~uvm_void~ inherit none of the +// UVM functionality, but such classes may be placed in ~uvm_void~-typed +// containers along with other UVM objects. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 5.2 +virtual class uvm_void; +endclass + +// Append/prepend symbolic values for order-dependent APIs +typedef enum {UVM_APPEND, UVM_PREPEND} uvm_apprepend; + +// Forward declaration since scope stack uses uvm_objects now +typedef class uvm_object; + +typedef class uvm_coreservice_t; +typedef class uvm_factory; + +typedef class uvm_config_db; +// m_uvm_config_obj_misc is an internal typedef for the uvm_misc.svh file +// to use. UVM users should use the uvm_config_object typedef +typedef uvm_config_db#(uvm_object) m_uvm_config_obj_misc; + + +typedef class uvm_comparer ; +typedef class uvm_packer ; +typedef class uvm_recorder ; +typedef class uvm_printer ; + +// Variable- uvm_global_random_seed +// +// Create a seed which is based off of the global seed which can be used to seed +// srandom processes but will change if the command line seed setting is +// changed. +// +int unsigned uvm_global_random_seed = $urandom; + + +// Class- uvm_seed_map +// +// This map is a seed map that can be used to update seeds. The update +// is done automatically by the seed hashing routine. The seed_table_lookup +// uses an instance name lookup and the seed_table inside a given map +// uses a type name for the lookup. +// +class uvm_seed_map; + int unsigned seed_table [string]; + int unsigned count [string]; +endclass + +uvm_seed_map uvm_random_seed_table_lookup [string]; + + +//------------------------------------------------------------------------------ +// Internal utility functions +//------------------------------------------------------------------------------ + +// Function- uvm_instance_scope +// +// A function that returns the scope that the UVM library lives in, either +// an instance, a module, or a package. +// +function string uvm_instance_scope(); + byte c; + int pos; + //first time through the scope is ~null~ and we need to calculate, afterwards it + //is correctly set. + + if(uvm_instance_scope != "") + return uvm_instance_scope; + + $swrite(uvm_instance_scope, "%m"); + //remove the extraneous .uvm_instance_scope piece or ::uvm_instance_scope + pos = uvm_instance_scope.len()-1; + c = uvm_instance_scope[pos]; + while(pos && (c != ".") && (c != ":")) + c = uvm_instance_scope[--pos]; + if(pos == 0) + uvm_report_error("SCPSTR", $sformatf("Illegal name %s in scope string",uvm_instance_scope)); + uvm_instance_scope = uvm_instance_scope.substr(0,pos); +endfunction + + +// Function- uvm_oneway_hash +// +// A one-way hash function that is useful for creating srandom seeds. An +// unsigned int value is generated from the string input. An initial seed can +// be used to seed the hash, if not supplied the uvm_global_random_seed +// value is used. Uses a CRC like functionality to minimize collisions. +// +parameter UVM_STR_CRC_POLYNOMIAL = 32'h04c11db6; +function int unsigned uvm_oneway_hash ( string string_in, int unsigned seed=0 ); + bit msb; + bit [7:0] current_byte; + bit [31:0] crc1; + + if(!seed) seed = uvm_global_random_seed; + uvm_oneway_hash = seed; + + crc1 = 32'hffffffff; + for (int _byte=0; _byte < string_in.len(); _byte++) begin + current_byte = string_in[_byte]; + if (current_byte == 0) break; + for (int _bit=0; _bit < 8; _bit++) begin + msb = crc1[31]; + crc1 <<= 1; + if (msb ^ current_byte[_bit]) begin + crc1 ^= UVM_STR_CRC_POLYNOMIAL; + crc1[0] = 1; + end + end + end + uvm_oneway_hash += ~{crc1[7:0], crc1[15:8], crc1[23:16], crc1[31:24]}; + +endfunction + + +// Function- uvm_create_random_seed +// +// Creates a random seed and updates the seed map so that if the same string +// is used again, a new value will be generated. The inst_id is used to hash +// by instance name and get a map of type name hashes which the type_id uses +// for its lookup. + +function int unsigned uvm_create_random_seed ( string type_id, string inst_id="" ); + uvm_seed_map seed_map; + + if(inst_id == "") + inst_id = "__global__"; + + if(!uvm_random_seed_table_lookup.exists(inst_id)) + uvm_random_seed_table_lookup[inst_id] = new; + seed_map = uvm_random_seed_table_lookup[inst_id]; + + type_id = {uvm_instance_scope(),type_id}; + + if(!seed_map.seed_table.exists(type_id)) begin + seed_map.seed_table[type_id] = uvm_oneway_hash ({type_id,"::",inst_id}, uvm_global_random_seed); + end + if (!seed_map.count.exists(type_id)) begin + seed_map.count[type_id] = 0; + end + + //can't just increment, otherwise too much chance for collision, so + //randomize the seed using the last seed as the seed value. Check if + //the seed has been used before and if so increment it. + seed_map.seed_table[type_id] = seed_map.seed_table[type_id]+seed_map.count[type_id]; + seed_map.count[type_id]++; + + return seed_map.seed_table[type_id]; +endfunction + + +// Function- uvm_object_value_str +// +// +function string uvm_object_value_str(uvm_object v); + if (v == null) + return ""; + uvm_object_value_str.itoa(v.get_inst_id()); + uvm_object_value_str = {"@",uvm_object_value_str}; +endfunction + + +// Function- uvm_leaf_scope +// +// +function string uvm_leaf_scope (string full_name, byte scope_separator = "."); + byte bracket_match; + int pos; + int bmatches; + + bmatches = 0; + case(scope_separator) + "[": bracket_match = "]"; + "(": bracket_match = ")"; + "<": bracket_match = ">"; + "{": bracket_match = "}"; + default: bracket_match = ""; + endcase + + //Only use bracket matching if the input string has the end match + if(bracket_match != "" && bracket_match != full_name[full_name.len()-1]) + bracket_match = ""; + + for(pos=full_name.len()-1; pos>0; --pos) begin + if(full_name[pos] == bracket_match) bmatches++; + else if(full_name[pos] == scope_separator) begin + bmatches--; + if(!bmatches || (bracket_match == "")) break; + end + end + if(pos) begin + if(scope_separator != ".") pos--; + uvm_leaf_scope = full_name.substr(pos+1,full_name.len()-1); + end + else begin + uvm_leaf_scope = full_name; + end +endfunction + + +// Function- uvm_bitstream_to_string +// +// +function string uvm_bitstream_to_string (uvm_bitstream_t value, int size, + uvm_radix_enum radix=UVM_NORADIX, + string radix_str=""); + // sign extend & don't show radix for negative values + if (radix == UVM_DEC && value[size-1] === 1) + return $sformatf("%0d", value); + + // TODO $countbits(value,'z) would be even better + if($isunknown(value)) begin + uvm_bitstream_t _t; + _t=0; + for(int idx=0;idx 0 && (arg[i] != "[")) begin + --i; + if((arg[i] == "*") || (arg[i] == "?")) i=0; + else if((arg[i] < "0") || (arg[i] > "9") && (arg[i] != "[")) begin + uvm_get_array_index_int = -1; //illegal integral index + i=0; + end + end + else begin + is_wildcard = 0; + return 0; + end + + if(i>0) begin + arg = arg.substr(i+1, arg.len()-2); + uvm_get_array_index_int = arg.atoi(); + is_wildcard = 0; + end +endfunction + + +// Function- uvm_get_array_index_string +// +// +function string uvm_get_array_index_string(string arg, output bit is_wildcard); + int i; + uvm_get_array_index_string = ""; + is_wildcard = 1; + i = arg.len() - 1; + if(arg[i] == "]") + while(i > 0 && (arg[i] != "[")) begin + if((arg[i] == "*") || (arg[i] == "?")) i=0; + --i; + end + if(i>0) begin + uvm_get_array_index_string = arg.substr(i+1, arg.len()-2); + is_wildcard = 0; + end +endfunction + + +// Function- uvm_is_array +// +// +function bit uvm_is_array(string arg); + return arg[arg.len()-1] == "]"; +endfunction + + +// Function- uvm_has_wildcard +// +// +function automatic bit uvm_has_wildcard (string arg); + uvm_has_wildcard = 0; + + //if it is a regex then return true + if( (arg.len() > 1) && (arg[0] == "/") && (arg[arg.len()-1] == "/") ) + return 1; + + //check if it has globs + foreach(arg[i]) + if( (arg[i] == "*") || (arg[i] == "+") || (arg[i] == "?") ) + uvm_has_wildcard = 1; + +endfunction + + +typedef class uvm_component; +typedef class uvm_root; +typedef class uvm_report_object; + +`ifdef UVM_ENABLE_DEPRECATED_API +//------------------------------------------------------------------------------ +// CLASS -- NODOCS -- uvm_utils #(TYPE,FIELD) +// +// This class contains useful template functions. +// +//------------------------------------------------------------------------------ + +class uvm_utils #(type TYPE=int, string FIELD="config"); + + typedef TYPE types_t[$]; + + // Function -- NODOCS -- find_all + // + // Recursively finds all component instances of the parameter type ~TYPE~, + // starting with the component given by ~start~. Uses . + + static function types_t find_all(uvm_component start); + uvm_component list[$]; + types_t types; + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.find_all("*",list,start); + foreach (list[i]) begin + TYPE typ; + if ($cast(typ,list[i])) + types.push_back(typ); + end + if (types.size() == 0) begin + `uvm_warning("find_type-no match",{"Instance of type '",TYPE::type_name, + " not found in component hierarchy beginning at ",start.get_full_name()}) + end + return types; + endfunction + + static function TYPE find(uvm_component start); + types_t types = find_all(start); + if (types.size() == 0) + return null; + if (types.size() > 1) begin + `uvm_warning("find_type-multi match",{"More than one instance of type '",TYPE::type_name, + " found in component hierarchy beginning at ",start.get_full_name()}) + return null; + end + return types[0]; + endfunction + + static function TYPE create_type_by_name(string type_name, string contxt); + uvm_object obj; + TYPE typ; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + + obj = factory.create_object_by_name(type_name,contxt,type_name); + if (!$cast(typ,obj)) + uvm_report_error("WRONG_TYPE",{"The type_name given '",type_name, + "' with context '",contxt,"' did not produce the expected type."}); + return typ; + endfunction + + + // Function -- NODOCS -- get_config + // + // This method gets the object config of type ~TYPE~ + // associated with component ~comp~. + // We check for the two kinds of error which may occur with this kind of + // operation. + + static function TYPE get_config(uvm_component comp, bit is_fatal); + uvm_object obj; + TYPE cfg; + + if (!m_uvm_config_obj_misc::get(comp,"",FIELD, obj)) begin + if (is_fatal) + comp.uvm_report_fatal("NO_SET_CFG", {"no set_config to field '", FIELD, + "' for component '",comp.get_full_name(),"'"}, + UVM_MEDIUM, `uvm_file , `uvm_line ); + else + comp.uvm_report_warning("NO_SET_CFG", {"no set_config to field '", FIELD, + "' for component '",comp.get_full_name(),"'"}, + UVM_MEDIUM, `uvm_file , `uvm_line ); + return null; + end + + if (!$cast(cfg, obj)) begin + if (is_fatal) + comp.uvm_report_fatal( "GET_CFG_TYPE_FAIL", + {"set_config_object with field name ",FIELD, + " is not of type '",TYPE::type_name,"'"}, + UVM_NONE , `uvm_file , `uvm_line ); + else + comp.uvm_report_warning( "GET_CFG_TYPE_FAIL", + {"set_config_object with field name ",FIELD, + " is not of type '",TYPE::type_name,"'"}, + UVM_NONE , `uvm_file , `uvm_line ); + end + + return cfg; + endfunction +endclass +`endif + +`ifdef UVM_USE_PROCESS_CONTAINER +class process_container_c; + process p; + function new(process p_); + p=p_; + endfunction +endclass +`endif + + +// this is an internal function and provides a string join independent of a streaming pack +function automatic string m_uvm_string_queue_join(ref string i[$]); +`ifndef QUESTA + m_uvm_string_queue_join = {>>{i}}; +`else + foreach(i[idx]) + m_uvm_string_queue_join = {m_uvm_string_queue_join,i[idx]}; +`endif +endfunction + + + diff --git a/test_regress/t/t_uvm/base/uvm_object.svh b/test_regress/t/t_uvm/base/uvm_object.svh index 4f8db82558..b50be204f0 100644 --- a/test_regress/t/t_uvm/base/uvm_object.svh +++ b/test_regress/t/t_uvm/base/uvm_object.svh @@ -1,13 +1,12 @@ // -//------------------------------------------------------------------------------ -// Copyright 2007-2011 Mentor Graphics Corporation +//----------------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation // Copyright 2014 Semifore // Copyright 2010-2018 Synopsys, Inc. // Copyright 2007-2018 Cadence Design Systems, Inc. // Copyright 2010-2012 AMD -// Copyright 2012-2018 NVIDIA Corporation -// Copyright 2012-2018 Cisco Systems, Inc. -// Copyright 2012 Accellera Systems Initiative +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, Inc. // Copyright 2017 Verific // All Rights Reserved Worldwide // @@ -24,64 +23,1353 @@ // CONDITIONS OF ANY KIND, either express or implied. See // the License for the specific language governing // permissions and limitations under the License. +//----------------------------------------------------------------------------- + + +typedef class uvm_report_object; +typedef class uvm_object_wrapper; +typedef class uvm_objection; +typedef class uvm_component; +typedef class uvm_resource_base; +typedef class uvm_resource; +typedef class uvm_field_op; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_object +// +// The uvm_object class is the base class for all UVM data and hierarchical +// classes. Its primary role is to define a set of methods for such common +// operations as , , , , and . Classes +// deriving from uvm_object must implement the pure virtual methods such as +// and . +// //------------------------------------------------------------------------------ -// SPDX-License-Identifier: Apache-2.0 +// @uvm-ieee 1800.2-2017 auto 5.3.1 +virtual class uvm_object extends uvm_void; + + + // Function -- NODOCS -- new + // + // Creates a new uvm_object with the given instance ~name~. If ~name~ is not + // supplied, the object is unnamed. + + extern function new (string name=""); + + + // Group -- NODOCS -- Seeding + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- use_uvm_seeding + // + // This bit enables or disables the UVM seeding mechanism. It globally affects + // the operation of the method. + // + // When enabled, UVM-based objects are seeded based on their type and full + // hierarchical name rather than allocation order. This improves random + // stability for objects whose instance names are unique across each type. + // The class is an example of a type that has a unique + // instance name. + + static bit use_uvm_seeding = 1; +`endif + + // Function -- NODOCS -- get_uvm_seeding + + // @uvm-ieee 1800.2-2017 auto 5.3.3.1 + extern static function bit get_uvm_seeding(); + + // Function -- NODOCS -- set_uvm_seeding + + // @uvm-ieee 1800.2-2017 auto 5.3.3.2 + extern static function void set_uvm_seeding(bit enable); + + // Function -- NODOCS -- reseed + // + // Calls ~srandom~ on the object to reseed the object using the UVM seeding + // mechanism, which sets the seed based on type name and instance name instead + // of based on instance position in a thread. + // + // If returns 0, then reseed() does + // not perform any function. + + // @uvm-ieee 1800.2-2017 auto 5.3.3.3 + extern function void reseed (); + + + // Group -- NODOCS -- Identification + + // Function -- NODOCS -- set_name + // + // Sets the instance name of this object, overwriting any previously + // given name. + + // @uvm-ieee 1800.2-2017 auto 5.3.4.1 + extern virtual function void set_name (string name); + + + // Function -- NODOCS -- get_name + // + // Returns the name of the object, as provided by the ~name~ argument in the + // constructor or method. + + // @uvm-ieee 1800.2-2017 auto 5.3.4.2 + extern virtual function string get_name (); + + + // Function -- NODOCS -- get_full_name + // + // Returns the full hierarchical name of this object. The default + // implementation is the same as , as uvm_objects do not inherently + // possess hierarchy. + // + // Objects possessing hierarchy, such as , override the default + // implementation. Other objects might be associated with component hierarchy + // but are not themselves components. For example, + // classes are typically associated with a . In this + // case, it is useful to override get_full_name to return the sequencer's + // full name concatenated with the sequence's name. This provides the sequence + // a full context, which is useful when debugging. + + // @uvm-ieee 1800.2-2017 auto 5.3.4.3 + extern virtual function string get_full_name (); + + + // Function -- NODOCS -- get_inst_id + // + // Returns the object's unique, numeric instance identifier. + + // @uvm-ieee 1800.2-2017 auto 5.3.4.4 + extern virtual function int get_inst_id (); + + + // Function -- NODOCS -- get_inst_count + // + // Returns the current value of the instance counter, which represents the + // total number of uvm_object-based objects that have been allocated in + // simulation. The instance counter is used to form a unique numeric instance + // identifier. + + extern static function int get_inst_count(); + + + // Function -- NODOCS -- get_type + // + // Returns the type-proxy (wrapper) for this object. The 's + // type-based override and creation methods take arguments of + // . This method, if implemented, can be used as convenient + // means of supplying those arguments. + // + // The default implementation of this method produces an error and returns + // ~null~. To enable use of this method, a user's subtype must implement a + // version that returns the subtype's wrapper. + // + // For example: + // + //| class cmd extends uvm_object; + //| typedef uvm_object_registry #(cmd) type_id; + //| static function type_id get_type(); + //| return type_id::get(); + //| endfunction + //| endclass + // + // Then, to use: + // + //| factory.set_type_override(cmd::get_type(),subcmd::get_type()); + // + // This function is implemented by the `uvm_*_utils macros, if employed. + + extern static function uvm_object_wrapper get_type (); + + + // Function -- NODOCS -- get_object_type + // + // Returns the type-proxy (wrapper) for this object. The 's + // type-based override and creation methods take arguments of + // . This method, if implemented, can be used as convenient + // means of supplying those arguments. This method is the same as the static + // method, but uses an already allocated object to determine + // the type-proxy to access (instead of using the static object). + // + // The default implementation of this method does a factory lookup of the + // proxy using the return value from . If the type returned + // by is not registered with the factory, then a ~null~ + // handle is returned. + // + // For example: + // + //| class cmd extends uvm_object; + //| typedef uvm_object_registry #(cmd) type_id; + //| static function type_id get_type(); + //| return type_id::get(); + //| endfunction + //| virtual function type_id get_object_type(); + //| return type_id::get(); + //| endfunction + //| endclass + // + // This function is implemented by the `uvm_*_utils macros, if employed. + + extern virtual function uvm_object_wrapper get_object_type (); + + + // Function -- NODOCS -- get_type_name + // + // This function returns the type name of the object, which is typically the + // type identifier enclosed in quotes. It is used for various debugging + // functions in the library, and it is used by the factory for creating + // objects. + // + // This function must be defined in every derived class. + // + // A typical implementation is as follows: + // + //| class mytype extends uvm_object; + //| ... + //| static function string type_name(); return "myType"; endfunction : type_name + //| + //| virtual function string get_type_name(); + //| return type_name; + //| endfunction + // + // We define the ~type_name~ static method to enable access to the type name + // without need of an object of the class, i.e., to enable access via the + // scope operator, ~mytype::type_name~. + + virtual function string get_type_name (); return ""; endfunction + + + // Group -- NODOCS -- Creation + + // Function -- NODOCS -- create + // + // The ~create~ method allocates a new object of the same type as this object + // and returns it via a base uvm_object handle. Every class deriving from + // uvm_object, directly or indirectly, must implement the create method. + // + // A typical implementation is as follows: + // + //| class mytype extends uvm_object; + //| ... + //| virtual function uvm_object create(string name=""); + //| mytype t = new(name); + //| return t; + //| endfunction + + virtual function uvm_object create (string name=""); return null; endfunction + + + // Function -- NODOCS -- clone + // + // The ~clone~ method creates and returns an exact copy of this object. + // + // The default implementation calls followed by . As clone is + // virtual, derived classes may override this implementation if desired. + + // @uvm-ieee 1800.2-2017 auto 5.3.5.2 + extern virtual function uvm_object clone (); + + + // Group -- NODOCS -- Printing + + // Function -- NODOCS -- print + // + // The ~print~ method deep-prints this object's properties in a format and + // manner governed by the given ~printer~ argument; if the ~printer~ argument + // is not provided, the global is used. See + // for more information on printer output formatting. See also + // , , and for details + // on the pre-defined printer "policies," or formatters, provided by the UVM. + // + // The ~print~ method is not virtual and must not be overloaded. To include + // custom information in the ~print~ and operations, derived classes + // must override the method and use the provided printer policy + // class to format the output. + + // @uvm-ieee 1800.2-2017 auto 5.3.6.1 + extern function void print (uvm_printer printer=null); + + + // Function -- NODOCS -- sprint + // + // The ~sprint~ method works just like the method, except the output + // is returned in a string rather than displayed. + // + // The ~sprint~ method is not virtual and must not be overloaded. To include + // additional fields in the and ~sprint~ operation, derived classes + // must override the method and use the provided printer policy + // class to format the output. The printer policy will manage all string + // concatenations and provide the string to ~sprint~ to return to the caller. + + // @uvm-ieee 1800.2-2017 auto 5.3.6.2 + extern function string sprint (uvm_printer printer=null); + + + // Function -- NODOCS -- do_print + // + // The ~do_print~ method is the user-definable hook called by and + // that allows users to customize what gets printed or sprinted + // beyond the field information provided by the `uvm_field_* macros, + // . + // + // The ~printer~ argument is the policy object that governs the format and + // content of the output. To ensure correct and operation, + // and to ensure a consistent output format, the ~printer~ must be used + // by all implementations. That is, instead of using ~$display~ or + // string concatenations directly, a ~do_print~ implementation must call + // through the ~printer's~ API to add information to be printed or sprinted. + // + // An example implementation of ~do_print~ is as follows: + // + //| class mytype extends uvm_object; + //| data_obj data; + //| int f1; + //| virtual function void do_print (uvm_printer printer); + //| super.do_print(printer); + //| printer.print_field_int("f1", f1, $bits(f1), UVM_DEC); + //| printer.print_object("data", data); + //| endfunction + // + // Then, to print and sprint the object, you could write: + // + //| mytype t = new; + //| t.print(); + //| uvm_report_info("Received",t.sprint()); + // + // See for information about the printer API. + + // @uvm-ieee 1800.2-2017 auto 5.3.6.3 + extern virtual function void do_print (uvm_printer printer); + + + // Function -- NODOCS -- convert2string + // + // This virtual function is a user-definable hook, called directly by the + // user, that allows users to provide object information in the form of + // a string. Unlike , there is no requirement to use a + // policy object. As such, the format and content of the output is fully + // customizable, which may be suitable for applications not requiring the + // consistent formatting offered by the // + // API. + // + // Fields declared in macros (`uvm_field_*), if used, will + // not automatically appear in calls to convert2string. + // + // An example implementation of convert2string follows. + // + //| class base extends uvm_object; + //| string field = "foo"; + //| virtual function string convert2string(); + //| convert2string = {"base_field=",field}; + //| endfunction + //| endclass + //| + //| class obj2 extends uvm_object; + //| string field = "bar"; + //| virtual function string convert2string(); + //| convert2string = {"child_field=",field}; + //| endfunction + //| endclass + //| + //| class obj extends base; + //| int addr = 'h123; + //| int data = 'h456; + //| bit write = 1; + //| obj2 child = new; + //| virtual function string convert2string(); + //| convert2string = {super.convert2string(), + //| $sformatf(" write=%0d addr=%8h data=%8h ",write,addr,data), + //| child.convert2string()}; + //| endfunction + //| endclass + // + // Then, to display an object, you could write: + // + //| obj o = new; + //| uvm_report_info("BusMaster",{"Sending:\n ",o.convert2string()}); + // + // The output will look similar to: + // + //| UVM_INFO @ 0: reporter [BusMaster] Sending: + //| base_field=foo write=1 addr=00000123 data=00000456 child_field=bar + + + // @uvm-ieee 1800.2-2017 auto 5.3.6.4 + extern virtual function string convert2string(); + + + // Group -- NODOCS -- Recording + + // Function -- NODOCS -- record + // + // The ~record~ method deep-records this object's properties according to an + // optional ~recorder~ policy. The method is not virtual and must not be + // overloaded. To include additional fields in the record operation, derived + // classes should override the method. + // + // The optional ~recorder~ argument specifies the recording policy, which + // governs how recording takes place. See + // for information. + // + // A simulator's recording mechanism is vendor-specific. By providing access + // via a common interface, the uvm_recorder policy provides vendor-independent + // access to a simulator's recording capabilities. + + // @uvm-ieee 1800.2-2017 auto 5.3.7.1 + extern function void record (uvm_recorder recorder=null); + + + // Function -- NODOCS -- do_record + // + // The ~do_record~ method is the user-definable hook called by the + // method. A derived class should override this method to include its fields + // in a record operation. + // + // The ~recorder~ argument is policy object for recording this object. A + // do_record implementation should call the appropriate recorder methods for + // each of its fields. Vendor-specific recording implementations are + // encapsulated in the ~recorder~ policy, thereby insulating user-code from + // vendor-specific behavior. See for more information. + // + // A typical implementation is as follows: + // + //| class mytype extends uvm_object; + //| data_obj data; + //| int f1; + //| function void do_record (uvm_recorder recorder); + //| recorder.record_field("f1", f1, $bits(f1), UVM_DEC); + //| recorder.record_object("data", data); + //| endfunction + + // @uvm-ieee 1800.2-2017 auto 5.3.7.2 + extern virtual function void do_record (uvm_recorder recorder); + -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- + // Group -- NODOCS -- Copying -// Status: MOCK + // Function -- NODOCS -- copy + // + // The copy makes this object a copy of the specified object. + // + // The ~copy~ method is not virtual and should not be overloaded in derived + // classes. To copy the fields of a derived class, that class should override + // the method. -// UVM MOCK -class uvm_copier; endclass + // @uvm-ieee 1800.2-2017 auto 5.3.8.1 + extern function void copy (uvm_object rhs, uvm_copier copier=null); + + + // Function -- NODOCS -- do_copy + // + // The ~do_copy~ method is the user-definable hook called by the method. + // A derived class should override this method to include its fields in a + // operation. + // + // A typical implementation is as follows: + // + //| class mytype extends uvm_object; + //| ... + //| int f1; + //| function void do_copy (uvm_object rhs); + //| mytype rhs_; + //| super.do_copy(rhs); + //| $cast(rhs_,rhs); + //| field_1 = rhs_.field_1; + //| endfunction + // + // The implementation must call ~super.do_copy~, and it must $cast the rhs + // argument to the derived type before copying. + + // @uvm-ieee 1800.2-2017 auto 5.3.8.2 + extern virtual function void do_copy (uvm_object rhs); + + + // Group -- NODOCS -- Comparing + + // Function -- NODOCS -- compare + // + // Deep compares members of this data object with those of the object provided + // in the ~rhs~ (right-hand side) argument, returning 1 on a match, 0 otherwise. + // + // The ~compare~ method is not virtual and should not be overloaded in derived + // classes. To compare the fields of a derived class, that class should + // override the method. + // + // The optional ~comparer~ argument specifies the comparison policy. It allows + // you to control some aspects of the comparison operation. It also stores the + // results of the comparison, such as field-by-field miscompare information + // and the total number of miscompares. If a compare policy is not provided, + // then the global ~uvm_default_comparer~ policy is used. See + // for more information. + + // @uvm-ieee 1800.2-2017 auto 5.3.9.1 + extern function bit compare (uvm_object rhs, uvm_comparer comparer=null); + + + // Function -- NODOCS -- do_compare + // + // The ~do_compare~ method is the user-definable hook called by the + // method. A derived class should override this method to include its fields + // in a compare operation. It should return 1 if the comparison succeeds, 0 + // otherwise. + // + // A typical implementation is as follows: + // + //| class mytype extends uvm_object; + //| ... + //| int f1; + //| virtual function bit do_compare (uvm_object rhs,uvm_comparer comparer); + //| mytype rhs_; + //| do_compare = super.do_compare(rhs,comparer); + //| $cast(rhs_,rhs); + //| do_compare &= comparer.compare_field_int("f1", f1, rhs_.f1); + //| endfunction + // + // A derived class implementation must call ~super.do_compare()~ to ensure its + // base class' properties, if any, are included in the comparison. Also, the + // rhs argument is provided as a generic uvm_object. Thus, you must ~$cast~ it + // to the type of this object before comparing. + // + // The actual comparison should be implemented using the uvm_comparer object + // rather than direct field-by-field comparison. This enables users of your + // class to customize how comparisons are performed and how much miscompare + // information is collected. See uvm_comparer for more details. + + // @uvm-ieee 1800.2-2017 auto 5.3.9.2 + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + + // Group -- NODOCS -- Packing + + // Function -- NODOCS -- pack + + // @uvm-ieee 1800.2-2017 auto 5.3.10.1 + extern function int pack (ref bit bitstream[], + input uvm_packer packer=null); + + // Function -- NODOCS -- pack_bytes + + // @uvm-ieee 1800.2-2017 auto 5.3.10.1 + extern function int pack_bytes (ref byte unsigned bytestream[], + input uvm_packer packer=null); + + // Function -- NODOCS -- pack_ints + // + // The pack methods bitwise-concatenate this object's properties into an array + // of bits, bytes, or ints. The methods are not virtual and must not be + // overloaded. To include additional fields in the pack operation, derived + // classes should override the method. + // + // The optional ~packer~ argument specifies the packing policy, which governs + // the packing operation. If a packer policy is not provided, the global + // policy is used. See for more information. + // + // The return value is the total number of bits packed into the given array. + // Use the array's built-in ~size~ method to get the number of bytes or ints + // consumed during the packing process. + + // @uvm-ieee 1800.2-2017 auto 5.3.10.1 + extern function int pack_ints (ref int unsigned intstream[], + input uvm_packer packer=null); + + // @uvm-ieee 1800.2-2017 auto 5.3.10.1 + extern function int pack_longints (ref longint unsigned longintstream[], + input uvm_packer packer=null); + + + // Function -- NODOCS -- do_pack + // + // The ~do_pack~ method is the user-definable hook called by the methods. + // A derived class should override this method to include its fields in a pack + // operation. + // + // The ~packer~ argument is the policy object for packing. The policy object + // should be used to pack objects. + // + // A typical example of an object packing itself is as follows + // + //| class mysubtype extends mysupertype; + //| ... + //| shortint myshort; + //| obj_type myobj; + //| byte myarray[]; + //| ... + //| function void do_pack (uvm_packer packer); + //| super.do_pack(packer); // pack mysupertype properties + //| packer.pack_field_int(myarray.size(), 32); + //| foreach (myarray) + //| packer.pack_field_int(myarray[index], 8); + //| packer.pack_field_int(myshort, $bits(myshort)); + //| packer.pack_object(myobj); + //| endfunction + // + // The implementation must call ~super.do_pack~ so that base class properties + // are packed as well. + // + // If your object contains dynamic data (object, string, queue, dynamic array, + // or associative array), and you intend to unpack into an equivalent data + // structure when unpacking, you must include meta-information about the + // dynamic data when packing as follows. + // + // - For queues, dynamic arrays, or associative arrays, pack the number of + // elements in the array in the 32 bits immediately before packing + // individual elements, as shown above. + // + // - For string data types, append a zero byte after packing the string + // contents. + // + // - For objects, pack 4 bits immediately before packing the object. For ~null~ + // objects, pack 4'b0000. For non-~null~ objects, pack 4'b0001. + // + // When the `uvm_field_* macros are used, + // , + // the above meta information is included. + // + // Packing order does not need to match declaration order. However, unpacking + // order must match packing order. + + // @uvm-ieee 1800.2-2017 auto 5.3.10.2 + extern virtual function void do_pack (uvm_packer packer); + + + // Group -- NODOCS -- Unpacking + + // Function -- NODOCS -- unpack + + // @uvm-ieee 1800.2-2017 auto 5.3.11.1 + extern function int unpack (ref bit bitstream[], + input uvm_packer packer=null); + + // Function -- NODOCS -- unpack_bytes + + // @uvm-ieee 1800.2-2017 auto 5.3.11.1 + extern function int unpack_bytes (ref byte unsigned bytestream[], + input uvm_packer packer=null); + + // Function -- NODOCS -- unpack_ints + // + // The unpack methods extract property values from an array of bits, bytes, or + // ints. The method of unpacking ~must~ exactly correspond to the method of + // packing. This is assured if (a) the same ~packer~ policy is used to pack + // and unpack, and (b) the order of unpacking is the same as the order of + // packing used to create the input array. + // + // The unpack methods are fixed (non-virtual) entry points that are directly + // callable by the user. To include additional fields in the + // operation, derived classes should override the method. + // + // The optional ~packer~ argument specifies the packing policy, which governs + // both the pack and unpack operation. If a packer policy is not provided, + // then the global ~uvm_default_packer~ policy is used. See uvm_packer for + // more information. + // + // The return value is the actual number of bits unpacked from the given array. + + // @uvm-ieee 1800.2-2017 auto 5.3.11.1 + extern function int unpack_ints (ref int unsigned intstream[], + input uvm_packer packer=null); + + // @uvm-ieee 1800.2-2017 auto 5.3.11.1 + extern function int unpack_longints (ref longint unsigned longintstream[], + input uvm_packer packer=null); + + + + // Function -- NODOCS -- do_unpack + // + // The ~do_unpack~ method is the user-definable hook called by the + // method. A derived class should override this method to include its fields + // in an unpack operation. + // + // The ~packer~ argument is the policy object for both packing and unpacking. + // It must be the same packer used to pack the object into bits. Also, + // do_unpack must unpack fields in the same order in which they were packed. + // See for more information. + // + // The following implementation corresponds to the example given in do_pack. + // + //| function void do_unpack (uvm_packer packer); + //| int sz; + //| super.do_unpack(packer); // unpack super's properties + //| sz = packer.unpack_field_int(myarray.size(), 32); + //| myarray.delete(); + //| for(int index=0; index into an equivalent data + // structure, you must have included meta-information about the dynamic data + // when it was packed. + // + // - For queues, dynamic arrays, or associative arrays, unpack the number of + // elements in the array from the 32 bits immediately before unpacking + // individual elements, as shown above. + // + // - For string data types, unpack into the new string until a ~null~ byte is + // encountered. + // + // - For objects, unpack 4 bits into a byte or int variable. If the value + // is 0, the target object should be set to ~null~ and unpacking continues to + // the next property, if any. If the least significant bit is 1, then the + // target object should be allocated and its properties unpacked. + + // @uvm-ieee 1800.2-2017 auto 5.3.11.2 + extern virtual function void do_unpack (uvm_packer packer); + + // @uvm-ieee 1800.2-2017 auto 5.3.13.1 + extern virtual function void do_execute_op ( uvm_field_op op); + + + // Group -- NODOCS -- Configuration +`ifdef UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- set_int_local + + extern virtual function void set_int_local (string field_name, + uvm_bitstream_t value, + bit recurse=1); + + // Function -- NODOCS -- set_string_local + + extern virtual function void set_string_local (string field_name, + string value, + bit recurse=1); + + // Function -- NODOCS -- set_object_local + // + // These methods provide write access to integral, string, and + // uvm_object-based properties indexed by a ~field_name~ string. The object + // designer choose which, if any, properties will be accessible, and overrides + // the appropriate methods depending on the properties' types. For objects, + // the optional ~clone~ argument specifies whether to clone the ~value~ + // argument before assignment. + // + // The global function is used to match the field names, so + // ~field_name~ may contain wildcards. + // + // An example implementation of all three methods is as follows. + // + //| class mytype extends uvm_object; + //| + //| local int myint; + //| local byte mybyte; + //| local shortint myshort; // no access + //| local string mystring; + //| local obj_type myobj; + //| + //| // provide access to integral properties + //| function void set_int_local(string field_name, uvm_bitstream_t value); + //| if (uvm_is_match (field_name, "myint")) + //| myint = value; + //| else if (uvm_is_match (field_name, "mybyte")) + //| mybyte = value; + //| endfunction + //| + //| // provide access to string properties + //| function void set_string_local(string field_name, string value); + //| if (uvm_is_match (field_name, "mystring")) + //| mystring = value; + //| endfunction + //| + //| // provide access to sub-objects + //| function void set_object_local(string field_name, uvm_object value, + //| bit clone=1); + //| if (uvm_is_match (field_name, "myobj")) begin + //| if (value != null) begin + //| obj_type tmp; + //| // if provided value is not correct type, produce error + //| if (!$cast(tmp, value) ) + //| /* error */ + //| else begin + //| if(clone) + //| $cast(myobj, tmp.clone()); + //| else + //| myobj = tmp; + //| end + //| end + //| else + //| myobj = null; // value is null, so simply assign null to myobj + //| end + //| endfunction + //| ... + // + // Although the object designer implements these methods to provide outside + // access to one or more properties, they are intended for internal use (e.g., + // for command-line debugging and auto-configuration) and should not be called + // directly by the user. + + extern virtual function void set_object_local (string field_name, + uvm_object value, + bit clone=1, + bit recurse=1); + +`endif // UVM_ENABLE_DEPRECATED_API + + // @uvm-ieee 1800.2-2017 auto 5.3.12 + extern virtual function void set_local(uvm_resource_base rsrc) ; + +`ifdef UVM_ENABLE_DEPRECATED_API + // Implementation artifact + uvm_resource_base m_set_local_rsrc; +`endif + + //--------------------------------------------------------------------------- + // **** Internal Methods and Properties *** + // Do not use directly + //--------------------------------------------------------------------------- + + extern local function void m_pack (inout uvm_packer packer); + extern local function void m_unpack_pre (inout uvm_packer packer); + extern local function int m_unpack_post (uvm_packer packer); + extern virtual function void m_unsupported_set_local(uvm_resource_base rsrc); + + // The print_matches bit causes an informative message to be printed + // when a field is set using one of the set methods. -class uvm_object; local string m_leaf_name; + local int m_inst_id; static protected int m_inst_count; - extern function new(string name=""); - extern function string get_name(); - extern function void set_name(string name); - extern function int get_inst_id(); + extern virtual function void __m_uvm_field_automation (uvm_object tmp_data__, + uvm_field_flag_t what__, + string str__); - virtual function string get_type_name (); return ""; endfunction + extern protected virtual function uvm_report_object m_get_report_object(); - extern virtual function void do_copy (uvm_object rhs); - extern virtual function string get_full_name (); endclass -// UVM 1:1* -function uvm_object::new(string name=""); - //$display("[mock] Created an object with name %s", name); +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// new +// --- + +function uvm_object::new (string name=""); + m_inst_id = m_inst_count++; m_leaf_name = name; endfunction -// UVM 1:1 +// get_uvm_seeding +// ------ + +function bit uvm_object::get_uvm_seeding(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_uvm_seeding(); +endfunction + +// set_uvm_seeding +// ------ + +function void uvm_object::set_uvm_seeding(bit enable); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + cs.set_uvm_seeding(enable); +endfunction + +// reseed +// ------ + +function void uvm_object::reseed (); + if(get_uvm_seeding()) + this.srandom(uvm_create_random_seed(get_type_name(), get_full_name())); +endfunction + + +// get type +// -------- + +function uvm_object_wrapper uvm_object::get_type(); + uvm_report_error("NOTYPID", "get_type not implemented in derived class.", UVM_NONE); + return null; +endfunction + + +// get inst_id +// ----------- + +function int uvm_object::get_inst_id(); + return m_inst_id; +endfunction + + +// get_object_type +// --------------- + +function uvm_object_wrapper uvm_object::get_object_type(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if(get_type_name() == "") return null; + return factory.find_wrapper_by_name(get_type_name()); +endfunction + + +// get inst_count +// -------------- + +function int uvm_object::get_inst_count(); + return m_inst_count; +endfunction + + +// get_name +// -------- + function string uvm_object::get_name (); return m_leaf_name; endfunction -// UVM 1:1 + +// get_full_name +// ------------- + +function string uvm_object::get_full_name (); + return get_name(); +endfunction + + +// set_name +// -------- + function void uvm_object::set_name (string name); m_leaf_name = name; endfunction -// UVM 1:1 -function int uvm_object::get_inst_id(); - return m_inst_id; + +// print +// ----- + +function void uvm_object::print(uvm_printer printer=null); + if (printer==null) printer = uvm_printer::get_default(); + $fwrite(printer.get_file(),sprint(printer)); +endfunction + + +// sprint +// ------ + +function string uvm_object::sprint(uvm_printer printer=null); + string name; + + if(printer==null) printer = uvm_printer::get_default(); + if (printer.get_active_object_depth() == 0) begin + printer.flush() ; + name = printer.get_root_enabled() ? get_full_name() : get_name(); + end + else begin + name = get_name(); + end + + printer.print_object(name,this); + + return printer.emit(); + +endfunction + + +// convert2string (virtual) +// -------------- + +function string uvm_object::convert2string(); + return ""; +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API +// set_int_local +// ------------- + +function void uvm_object::set_int_local (string field_name, + uvm_bitstream_t value, + bit recurse=1); + uvm_field_op field_op = uvm_field_op::m_get_available_op(); + uvm_resource_base rsrc_base = m_set_local_rsrc; + if (rsrc_base == null) begin + uvm_resource#(uvm_bitstream_t) rsrc = new(field_name); + rsrc.write(value); + rsrc_base = rsrc; + end + field_op.set(UVM_SET, null, rsrc_base); + do_execute_op(field_op); + field_op.m_recycle(); + m_set_local_rsrc = null; +endfunction + + +// set_object_local +// ---------------- + +function void uvm_object::set_object_local (string field_name, + uvm_object value, + bit clone=1, + bit recurse=1); + uvm_field_op field_op = uvm_field_op::m_get_available_op(); + uvm_resource_base rsrc_base = m_set_local_rsrc; + if (rsrc_base == null) begin + uvm_resource#(uvm_object) rsrc = new(field_name); + if (clone && (value != null)) begin + uvm_object cc = value.clone(); + if (cc != null) cc.set_name(field_name); + rsrc.write(cc); + end + else + rsrc.write(value); + rsrc_base = rsrc; + end + field_op.set(UVM_SET, null, rsrc_base); + do_execute_op(field_op); + field_op.m_recycle(); + m_set_local_rsrc = null; +endfunction + + +// set_string_local +// ---------------- +function void uvm_object::set_string_local (string field_name, + string value, + bit recurse=1); + + uvm_field_op field_op = uvm_field_op::m_get_available_op(); + uvm_resource_base rsrc_base = m_set_local_rsrc; + if (rsrc_base == null) begin + uvm_resource#(string) rsrc = new(field_name); + rsrc.write(value); + rsrc_base = rsrc; + end + field_op.set(UVM_SET, null, rsrc_base); + do_execute_op(field_op); + field_op.m_recycle(); + m_set_local_rsrc = null; +endfunction +`endif // UVM_ENABLE_DEPRECATED_API + + +// set_local +// ---------------- + +function void uvm_object::set_local(uvm_resource_base rsrc) ; + if(rsrc==null) begin + return ; + end + else begin +`ifdef UVM_ENABLE_DEPRECATED_API + bit success; + uvm_object obj; + m_set_local_rsrc = rsrc; + `uvm_resource_read(success, + rsrc, + uvm_object, + obj, + this) + if (success) begin + set_object_local(rsrc.get_name(), obj, 0); + end + else begin + string str; + `uvm_resource_read(success, + rsrc, + string, + str, + this) + if (success) begin + set_string_local(rsrc.get_name(), str); + end + else begin + uvm_bitstream_t bits; + `uvm_resource_builtin_int_read(success, + rsrc, + bits, + this) + if (success) begin + set_int_local(rsrc.get_name(), bits); + end + end + end + if (!success) +`endif + + begin + uvm_field_op op; + op = uvm_field_op::m_get_available_op(); + op.set(UVM_SET,null,rsrc); + this.do_execute_op(op); + op.m_recycle(); + end + end endfunction -// UVM 1:1 + +// m_unsupported_set_local +// ---------------------- +// + +function void uvm_object::m_unsupported_set_local(uvm_resource_base rsrc); + + return; +endfunction + + +// clone +// ----- + +function uvm_object uvm_object::clone(); + uvm_object tmp; + tmp = this.create(get_name()); + if(tmp == null) + uvm_report_warning("CRFLD", $sformatf("The create method failed for %s, object cannot be cloned", get_name()), UVM_NONE); + else + tmp.copy(this); + return(tmp); +endfunction + + +// copy +// ---- + +function void uvm_object::copy (uvm_object rhs, uvm_copier copier=null); +uvm_coreservice_t coreservice ; +uvm_copier m_copier; + + if(rhs == null) begin + `uvm_error("OBJ/COPY","Passing a null object to be copied") + return; + end + + if(copier == null) begin + coreservice = uvm_coreservice_t::get() ; + m_copier = coreservice.get_default_copier() ; + end + else + m_copier = copier; + // Copier is available. check depth as and flush it. Sec 5.3.8.1 + if(m_copier.get_active_object_depth() == 0) + m_copier.flush(); + + m_copier.copy_object(this,rhs); +endfunction + + +// do_copy +// ------- + function void uvm_object::do_copy (uvm_object rhs); return; endfunction -// UVM 1:1 -function string uvm_object::get_full_name (); - return get_name(); + +// compare +// ------- + +function bit uvm_object::compare (uvm_object rhs, + uvm_comparer comparer=null); + if (comparer == null) comparer = uvm_comparer::get_default(); + if (comparer.get_active_object_depth() == 0) + comparer.flush() ; + compare = comparer.compare_object(get_name(),this,rhs); + +endfunction + + +// do_compare +// ---------- + +function bit uvm_object::do_compare (uvm_object rhs, + uvm_comparer comparer); + return 1; +endfunction + + +// __m_uvm_field_automation +// ------------------ + +function void uvm_object::__m_uvm_field_automation (uvm_object tmp_data__, + uvm_field_flag_t what__, + string str__ ); + return; +endfunction + + + +// do_print (virtual override) +// ------------ + +function void uvm_object::do_print(uvm_printer printer); + return; +endfunction + + +// m_pack +// ------ + +function void uvm_object::m_pack (inout uvm_packer packer); + if (packer == null) + packer = uvm_packer::get_default(); + if(packer.get_active_object_depth() == 0) + packer.flush(); + packer.pack_object(this); + +endfunction + + +// pack +// ---- + +function int uvm_object::pack (ref bit bitstream [], + input uvm_packer packer =null ); + m_pack(packer); + packer.get_packed_bits(bitstream); + return packer.get_packed_size(); +endfunction + +// pack_bytes +// ---------- + +function int uvm_object::pack_bytes (ref byte unsigned bytestream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_bytes(bytestream); + return packer.get_packed_size(); +endfunction + + +// pack_ints +// --------- + +function int uvm_object::pack_ints (ref int unsigned intstream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_ints(intstream); + return packer.get_packed_size(); +endfunction + +// pack_longints +// --------- + +function int uvm_object::pack_longints (ref longint unsigned longintstream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_longints(longintstream); + return packer.get_packed_size(); +endfunction + + +// do_pack +// ------- + +function void uvm_object::do_pack (uvm_packer packer ); + if (packer == null) + `uvm_error("UVM/OBJ/PACK/NULL", "uvm_object::do_pack called with null packer!") + return; +endfunction + + +// m_unpack_pre +// ------------ + +function void uvm_object::m_unpack_pre (inout uvm_packer packer); + if (packer == null) + packer = uvm_packer::get_default(); + if(packer.get_active_object_depth() == 0) + packer.flush(); + +endfunction + + +// m_unpack_post +// ------------- + +function int uvm_object::m_unpack_post (uvm_packer packer); + int size_before_unpack = packer.get_packed_size(); + packer.unpack_object(this); + return size_before_unpack - packer.get_packed_size(); +endfunction + + +// unpack +// ------ + +function int uvm_object::unpack (ref bit bitstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_bits(bitstream); + return m_unpack_post(packer); +endfunction + + +// unpack_bytes +// ------------ + +function int uvm_object::unpack_bytes (ref byte unsigned bytestream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_bytes(bytestream); + return m_unpack_post(packer); +endfunction + + +// unpack_ints +// ----------- + +function int uvm_object::unpack_ints (ref int unsigned intstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_ints(intstream); + return m_unpack_post(packer); +endfunction + +// unpack_longints +// ----------- + +function int uvm_object::unpack_longints (ref longint unsigned longintstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_longints(longintstream); + return m_unpack_post(packer); +endfunction + + +function void uvm_object::do_execute_op ( uvm_field_op op); + +endfunction + + +// do_unpack +// --------- + +function void uvm_object::do_unpack (uvm_packer packer); + if (packer == null) + `uvm_error("UVM/OBJ/UNPACK/NULL", "uvm_object::do_unpack called with null packer!") + return; +endfunction + + +// record +// ------ + +function void uvm_object::record (uvm_recorder recorder=null); + + if(recorder == null) + return; + + recorder.record_object(get_name(), this); +endfunction + + +// do_record (virtual) +// --------- + +function void uvm_object::do_record (uvm_recorder recorder); + return; +endfunction + + +// m_get_report_object +// ------------------- + +function uvm_report_object uvm_object::m_get_report_object(); + return null; endfunction diff --git a/test_regress/t/t_uvm/base/uvm_object_globals.svh b/test_regress/t/t_uvm/base/uvm_object_globals.svh index 6d0fa347da..d85b6a14e8 100644 --- a/test_regress/t/t_uvm/base/uvm_object_globals.svh +++ b/test_regress/t/t_uvm/base/uvm_object_globals.svh @@ -1,12 +1,13 @@ -// SPDX-License-Identifier: Apache-2.0 // //------------------------------------------------------------------------------ -// Copyright 2007-2011 Mentor Graphics Corporation -// Copyright 2017 Intel Corporation -// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. // Copyright 2007-2018 Cadence Design Systems, Inc. -// Copyright 2010 AMD -// Copyright 2015-2018 NVIDIA Corporation +// Copyright 2013 Verilab +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2012-2018 Cisco Systems, Inc. // All Rights Reserved Worldwide // // Licensed under the Apache License, Version 2.0 (the @@ -24,19 +25,458 @@ // permissions and limitations under the License. //------------------------------------------------------------------------------ -typedef enum { UVM_PHASE_UNINITIALIZED = 0, - UVM_PHASE_DORMANT = 1, - UVM_PHASE_SCHEDULED = 2, - UVM_PHASE_SYNCING = 4, - UVM_PHASE_STARTED = 8, - UVM_PHASE_EXECUTING = 16, - UVM_PHASE_READY_TO_END = 32, - UVM_PHASE_ENDED = 64, - UVM_PHASE_CLEANUP = 128, - UVM_PHASE_DONE = 256, - UVM_PHASE_JUMPING = 512 - } uvm_phase_state; +//------------------------------------------------------------------------------ +// +// Section --NODOCS-- Types and Enumerations +// +//------------------------------------------------------------------------------ + +//------------------------ +// Group --NODOCS-- Field automation +//------------------------ + + +parameter UVM_STREAMBITS = `UVM_MAX_STREAMBITS; + + +// Type --NODOCS-- uvm_bitstream_t +// +// The bitstream type is used as a argument type for passing integral values +// in such methods as , , +// , , +// and . + +typedef logic signed [UVM_STREAMBITS-1:0] uvm_bitstream_t; + +// Type --NODOCS-- uvm_integral_t +// +// The integral type is used as a argument type for passing integral values +// of 64 bits or less in such methods as +// , , +// and . +// + +typedef logic signed [63:0] uvm_integral_t; + + + +// The number of least significant bits of uvm_field_flag_t which are reserved for this +// implementation. Derived from the value of UVM_RADIX which uses the most significant subset. +parameter UVM_FIELD_FLAG_RESERVED_BITS = 28; + +// The type for storing flag values passed to the uvm_field_* macros. +typedef bit [`UVM_FIELD_FLAG_SIZE-1 : 0] uvm_field_flag_t; + +// Enum -- NODOCS -- uvm_radix_enum +// +// Specifies the radix to print or record in. +// +// UVM_BIN - Selects binary (%b) format +// UVM_DEC - Selects decimal (%d) format +// UVM_UNSIGNED - Selects unsigned decimal (%u) format +// UVM_UNFORMAT2 - Selects unformatted 2 value data (%u) format +// UVM_UNFORMAT4 - Selects unformatted 4 value data (%z) format +// UVM_OCT - Selects octal (%o) format +// UVM_HEX - Selects hexadecimal (%h) format +// UVM_STRING - Selects string (%s) format +// UVM_TIME - Selects time (%t) format +// UVM_ENUM - Selects enumeration value (name) format +// UVM_REAL - Selects real (%g) in exponential or decimal format, +// whichever format results in the shorter printed output +// UVM_REAL_DEC - Selects real (%f) in decimal format +// UVM_REAL_EXP - Selects real (%e) in exponential format + +typedef enum uvm_field_flag_t { + UVM_BIN = 'h1000000, + UVM_DEC = 'h2000000, + UVM_UNSIGNED = 'h3000000, + UVM_UNFORMAT2 = 'h4000000, + UVM_UNFORMAT4 = 'h5000000, + UVM_OCT = 'h6000000, + UVM_HEX = 'h7000000, + UVM_STRING = 'h8000000, + UVM_TIME = 'h9000000, + UVM_ENUM = 'ha000000, + UVM_REAL = 'hb000000, + UVM_REAL_DEC = 'hc000000, + UVM_REAL_EXP = 'hd000000, + UVM_NORADIX = 0 +} uvm_radix_enum; + +parameter UVM_RADIX = 'hf000000; //4 bits setting the radix + + +// Function- uvm_radix_to_string + +function string uvm_radix_to_string(uvm_radix_enum radix); + case(radix) + UVM_BIN: return "b"; + UVM_OCT: return "o"; + UVM_DEC: return "d"; + UVM_HEX: return "h"; + UVM_UNSIGNED: return "u"; + UVM_UNFORMAT2: return "u"; + UVM_UNFORMAT4: return "z"; + UVM_STRING: return "s"; + UVM_TIME: return "t"; + UVM_ENUM: return "s"; + UVM_REAL: return "g"; + UVM_REAL_DEC: return "f"; + UVM_REAL_EXP: return "e"; + default: return "x"; //hex + endcase +endfunction + + +// Enum --NODOCS-- uvm_recursion_policy_enum +// +// Specifies the policy for copying objects. +// +// UVM_DEEP - Objects are deep copied (object must implement method) +// UVM_SHALLOW - Objects are shallow copied using default SV copy. +// UVM_REFERENCE - Only object handles are copied. + +typedef enum uvm_field_flag_t { + UVM_DEFAULT_POLICY = 0, + UVM_DEEP = (1<<16), + UVM_SHALLOW = (1<<17), + UVM_REFERENCE = (1<<18) + } uvm_recursion_policy_enum; + +// UVM_RECURSION is a mask for uvm_recursion_policy_enum, similar to +// UVM_RADIX for uvm_radix_enum. Flags can be AND'd with the mask +// before casting into the enum, a`la: +// +//| uvm_recursion_policy_enum foo; +//| foo = uvm_recursion_policy_enum'(flags&UVM_RECURSION); +// +parameter UVM_RECURSION = (UVM_DEEP|UVM_SHALLOW|UVM_REFERENCE); + + +// Enum --NODOCS-- uvm_active_passive_enum +// +// Convenience value to define whether a component, usually an agent, +// is in "active" mode or "passive" mode. +// +// UVM_PASSIVE - "Passive" mode +// UVM_ACTIVE - "Active" mode +typedef enum bit { UVM_PASSIVE=0, UVM_ACTIVE=1 } uvm_active_passive_enum; + + +// Parameter --NODOCS-- `uvm_field_* macro flags +// +// Defines what operations a given field should be involved in. +// Bitwise OR all that apply. +// +// UVM_DEFAULT - All field operations turned on +// UVM_COPY - Field will participate in +// UVM_COMPARE - Field will participate in +// UVM_PRINT - Field will participate in +// UVM_RECORD - Field will participate in +// UVM_PACK - Field will participate in +// +// UVM_NOCOPY - Field will not participate in +// UVM_NOCOMPARE - Field will not participate in +// UVM_NOPRINT - Field will not participate in +// UVM_NORECORD - Field will not participate in +// UVM_NOPACK - Field will not participate in +// +// UVM_DEEP - Object field will be deep copied +// UVM_SHALLOW - Object field will be shallow copied +// UVM_REFERENCE - Object field will copied by reference +// +// UVM_READONLY - Object field will NOT be automatically configured. + +parameter uvm_field_flag_t UVM_MACRO_NUMFLAGS = 19; +//A=ABSTRACT Y=PHYSICAL +//F=REFERENCE, S=SHALLOW, D=DEEP +//K=PACK, R=RECORD, P=PRINT, M=COMPARE, C=COPY +//--------------------------- AYFSD K R P M C +parameter uvm_field_flag_t UVM_DEFAULT = 'b000010101010101; +parameter uvm_field_flag_t UVM_ALL_ON = 'b000000101010101; +parameter uvm_field_flag_t UVM_FLAGS_ON = 'b000000101010101; +parameter uvm_field_flag_t UVM_FLAGS_OFF = 0; + +//Values are OR'ed into a 32 bit value +//and externally +parameter uvm_field_flag_t UVM_COPY = (1<<0); +parameter uvm_field_flag_t UVM_NOCOPY = (1<<1); +parameter uvm_field_flag_t UVM_COMPARE = (1<<2); +parameter uvm_field_flag_t UVM_NOCOMPARE = (1<<3); +parameter uvm_field_flag_t UVM_PRINT = (1<<4); +parameter uvm_field_flag_t UVM_NOPRINT = (1<<5); +parameter uvm_field_flag_t UVM_RECORD = (1<<6); +parameter uvm_field_flag_t UVM_NORECORD = (1<<7); +parameter uvm_field_flag_t UVM_PACK = (1<<8); +parameter uvm_field_flag_t UVM_NOPACK = (1<<9); +parameter uvm_field_flag_t UVM_UNPACK = (1<<10); +parameter uvm_field_flag_t UVM_NOUNPACK = UVM_NOPACK; +parameter uvm_field_flag_t UVM_SET = (1<<11); +parameter uvm_field_flag_t UVM_NOSET = (1<<12); +`ifdef UVM_ENABLE_DEPRECATED_API +parameter uvm_field_flag_t UVM_PHYSICAL = (1<<13); +parameter uvm_field_flag_t UVM_ABSTRACT = (1<<14); +parameter uvm_field_flag_t UVM_READONLY = UVM_NOSET; +`endif +parameter uvm_field_flag_t UVM_NODEFPRINT = (1<<15); //?? +//parameter UVM_DEEP = (1<<16); +//parameter UVM_SHALLOW = (1<<17); +//parameter UVM_REFERENCE = (1<<18); + +//Extra values that are used for extra methods +parameter uvm_field_flag_t UVM_MACRO_EXTRAS = (1< task is +// being executed. +// UVM_PRE_BODY - The sequence is started and the +// task is +// being executed. +// UVM_BODY - The sequence is started and the +// task is +// being executed. +// UVM_ENDED - The sequence has completed the execution of the +// task. +// UVM_POST_BODY - The sequence is started and the +// task is +// being executed. +// UVM_POST_START - The sequence is started and the +// task is +// being executed. +// UVM_STOPPED - The sequence has been forcibly ended by issuing a +// on the sequence. +// UVM_FINISHED - The sequence is completely finished executing. +typedef enum +{ + UVM_CREATED = 1, + UVM_PRE_START = 2, + UVM_PRE_BODY = 4, + UVM_BODY = 8, + UVM_POST_BODY = 16, + UVM_POST_START= 32, + UVM_ENDED = 64, + UVM_STOPPED = 128, + UVM_FINISHED = 256 +} uvm_sequence_state; + +typedef uvm_sequence_state uvm_sequence_state_enum; // backward compat + + +// Enum --NODOCS-- uvm_sequence_lib_mode +// +// Specifies the random selection mode of a sequence library +// +// UVM_SEQ_LIB_RAND - Random sequence selection +// UVM_SEQ_LIB_RANDC - Random cyclic sequence selection +// UVM_SEQ_LIB_ITEM - Emit only items, no sequence execution +// UVM_SEQ_LIB_USER - Apply a user-defined random-selection algorithm + +typedef enum +{ + UVM_SEQ_LIB_RAND, + UVM_SEQ_LIB_RANDC, + UVM_SEQ_LIB_ITEM, + UVM_SEQ_LIB_USER +} uvm_sequence_lib_mode; + + + +//--------------- +// Group --NODOCS-- Phasing +//--------------- + +// Enum --NODOCS-- uvm_phase_type +// +// This is an attribute of a object which defines the phase +// type. +// +// UVM_PHASE_IMP - The phase object is used to traverse the component +// hierarchy and call the component phase method as +// well as the ~phase_started~ and ~phase_ended~ callbacks. +// These nodes are created by the phase macros, +// `uvm_builtin_task_phase, `uvm_builtin_topdown_phase, +// and `uvm_builtin_bottomup_phase. These nodes represent +// the phase type, i.e. uvm_run_phase, uvm_main_phase. +// +// UVM_PHASE_NODE - The object represents a simple node instance in +// the graph. These nodes will contain a reference to +// their corresponding IMP object. +// +// UVM_PHASE_SCHEDULE - The object represents a portion of the phasing graph, +// typically consisting of several NODE types, in series, +// parallel, or both. +// +// UVM_PHASE_TERMINAL - This internal object serves as the termination NODE +// for a SCHEDULE phase object. +// +// UVM_PHASE_DOMAIN - This object represents an entire graph segment that +// executes in parallel with the 'run' phase. +// Domains may define any network of NODEs and +// SCHEDULEs. The built-in domain, ~uvm~, consists +// of a single schedule of all the run-time phases, +// starting with ~pre_reset~ and ending with +// ~post_shutdown~. +// typedef enum { UVM_PHASE_IMP, UVM_PHASE_NODE, UVM_PHASE_TERMINAL, @@ -44,3 +484,234 @@ typedef enum { UVM_PHASE_IMP, UVM_PHASE_DOMAIN, UVM_PHASE_GLOBAL } uvm_phase_type; + + +// Enum --NODOCS-- uvm_phase_state +// --------------------- +// +// The set of possible states of a phase. This is an attribute of a schedule +// node in the graph, not of a phase, to maintain independent per-domain state +// +// UVM_PHASE_UNINITIALIZED - The state is uninitialized. This is the default +// state for phases, and for nodes which have not yet been added to +// a schedule. +// +// UVM_PHASE_DORMANT - The schedule is not currently operating on the phase +// node, however it will be scheduled at some point in the future. +// +// UVM_PHASE_SCHEDULED - At least one immediate predecessor has completed. +// Scheduled phases block until all predecessors complete or +// until a jump is executed. +// +// UVM_PHASE_SYNCING - All predecessors complete, checking that all synced +// phases (e.g. across domains) are at or beyond this point +// +// UVM_PHASE_STARTED - phase ready to execute, running phase_started() callback +// +// UVM_PHASE_EXECUTING - An executing phase is one where the phase callbacks are +// being executed. Its process is tracked by the phaser. +// +// UVM_PHASE_READY_TO_END - no objections remain in this phase or in any +// predecessors of its successors or in any sync'd phases. This +// state indicates an opportunity for any phase that needs extra +// time for a clean exit to raise an objection, thereby causing a +// return to UVM_PHASE_EXECUTING. If no objection is raised, state +// will transition to UVM_PHASE_ENDED after a delta cycle. +// (An example of predecessors of successors: The successor to +// phase 'run' is 'extract', whose predecessors are 'run' and +// 'post_shutdown'. Therefore, 'run' will go to this state when +// both its objections and those of 'post_shutdown' are all dropped. +// +// UVM_PHASE_ENDED - phase completed execution, now running phase_ended() callback +// +// UVM_PHASE_JUMPING - all processes related to phase are being killed and all +// predecessors are forced into the DONE state. +// +// UVM_PHASE_CLEANUP - all processes related to phase are being killed +// +// UVM_PHASE_DONE - A phase is done after it terminated execution. Becoming +// done may enable a waiting successor phase to execute. +// +// The state transitions occur as follows: +// +//| UNINITIALIZED -> DORMANT -> SCHED -> SYNC -> START -> EXEC -> READY -> END -+-> CLEAN -> DONE +//| ^ | +//| | <-- jump_to | +//| +-------------------------------------------- JUMPING< -+ + + typedef enum { UVM_PHASE_UNINITIALIZED = 0, + UVM_PHASE_DORMANT = 1, + UVM_PHASE_SCHEDULED = 2, + UVM_PHASE_SYNCING = 4, + UVM_PHASE_STARTED = 8, + UVM_PHASE_EXECUTING = 16, + UVM_PHASE_READY_TO_END = 32, + UVM_PHASE_ENDED = 64, + UVM_PHASE_CLEANUP = 128, + UVM_PHASE_DONE = 256, + UVM_PHASE_JUMPING = 512 + } uvm_phase_state; + + + +// Enum --NODOCS-- uvm_wait_op +// +// Specifies the operand when using methods like . +// +// UVM_EQ - equal +// UVM_NE - not equal +// UVM_LT - less than +// UVM_LTE - less than or equal to +// UVM_GT - greater than +// UVM_GTE - greater than or equal to +// +typedef enum { UVM_LT, + UVM_LTE, + UVM_NE, + UVM_EQ, + UVM_GT, + UVM_GTE +} uvm_wait_op; + + +//------------------ +// Group --NODOCS-- Objections +//------------------ + +// Enum --NODOCS-- uvm_objection_event +// +// Enumerated the possible objection events one could wait on. See +// . +// +// UVM_RAISED - an objection was raised +// UVM_DROPPED - an objection was raised +// UVM_ALL_DROPPED - all objections have been dropped +// +typedef enum { UVM_RAISED = 'h01, + UVM_DROPPED = 'h02, + UVM_ALL_DROPPED = 'h04 +} uvm_objection_event; + +`ifdef UVM_ENABLE_DEPRECATED_API + +//------------------------------ +// Group --NODOCS-- Default Policy Classes +//------------------------------ +// +// Policy classes copying, comparing, packing, unpacking, and recording +// -based objects. + + +typedef class uvm_printer; +typedef class uvm_table_printer; +typedef class uvm_tree_printer; +typedef class uvm_line_printer; +typedef class uvm_comparer; +typedef class uvm_packer; +typedef class uvm_tr_database; +typedef class uvm_text_tr_database; +typedef class uvm_recorder; + + +// Variable --NODOCS-- uvm_default_table_printer +// +// The table printer is a global object that can be used with +// to get tabular style printing. + +uvm_table_printer uvm_default_table_printer = new(); + + +// Variable --NODOCS-- uvm_default_tree_printer +// +// The tree printer is a global object that can be used with +// to get multi-line tree style printing. + +uvm_tree_printer uvm_default_tree_printer = new(); + + +// Variable --NODOCS-- uvm_default_line_printer +// +// The line printer is a global object that can be used with +// to get single-line style printing. + +uvm_line_printer uvm_default_line_printer = new(); + + +// Variable --NODOCS-- uvm_default_printer +// +// The default printer policy. Used when calls to +// or do not specify a printer policy. +// +// The default printer may be set to any legal derived type, +// including the global line, tree, and table printers described above. + +uvm_printer uvm_default_printer = uvm_default_table_printer; + + +// Variable --NODOCS-- uvm_default_packer +// +// The default packer policy. Used when calls to +// and do not specify a packer policy. + +uvm_packer uvm_default_packer = new(); + + +// Variable --NODOCS-- uvm_default_comparer +// +// +// The default compare policy. Used when calls to +// do not specify a comparer policy. + +uvm_comparer uvm_default_comparer = new(); // uvm_comparer::init(); + +`endif //UVM_ENABLE_DEPRECATED_API + +typedef int UVM_FILE; + +parameter UVM_FILE UVM_STDIN = 32'h8000_0000; +parameter UVM_FILE UVM_STDOUT = 32'h8000_0001; +parameter UVM_FILE UVM_STDERR = 32'h8000_0002; + +// Type: uvm_core_state +// Implementation of the uvm_core_state enumeration, as defined +// in section F.2.10 of 1800.2-2017. +// +// *Note:* In addition to the states defined in section F.2.10, +// this implementation includes the following additional states. +// +// UVM_CORE_PRE_INIT - The method has been invoked at least +// once, however the core service has yet to be +// determined/assigned. Additional calls to uvm_init +// while in this state will result in a fatal message +// being generated, as the library can not determine +// the correct core service. +// +// UVM_CORE_INITIALIZING - The method has been called at least +// once, and the core service has been determined. +// Once in this state, it is safe to query +// . +// +// UVM_CORE_POST_INIT - Included for consistency, this is equivalent to +// ~UVM_CORE_INITIALIZED~ in 1800.2-2017. +// +// @uvm-contrib Potential contribution to 1800.2 + +// @uvm-ieee 1800.2-2017 manual F.2.10 +typedef enum { + UVM_CORE_UNINITIALIZED, + UVM_CORE_PRE_INIT, + UVM_CORE_INITIALIZING, + UVM_CORE_INITIALIZED, // UVM_CORE_POST_INIT + UVM_CORE_PRE_RUN, + UVM_CORE_RUNNING, + UVM_CORE_POST_RUN, + UVM_CORE_FINISHED, + UVM_CORE_PRE_ABORT, + UVM_CORE_ABORTED +} uvm_core_state; + +uvm_core_state m_uvm_core_state = UVM_CORE_UNINITIALIZED; +parameter uvm_core_state UVM_CORE_POST_INIT = UVM_CORE_INITIALIZED; + +typedef class uvm_object_wrapper; +uvm_object_wrapper uvm_deferred_init[$]; diff --git a/test_regress/t/t_uvm/base/uvm_objection.svh b/test_regress/t/t_uvm/base/uvm_objection.svh new file mode 100644 index 0000000000..c68de23499 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_objection.svh @@ -0,0 +1,1244 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2014 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +//---------------------------------------------------------------------- + +`ifndef UVM_OBJECTION_SVH +`define UVM_OBJECTION_SVH + +typedef 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 -- NODOCS -- Objection Mechanism +//------------------------------------------------------------------------------ +// The following classes define the objection mechanism and end-of-test +// functionality, which is based on . +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- 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 , or it can be set for all +// objections from the command line using the option +UVM_OBJECTION_TRACE. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 10.5.1 +// @uvm-ieee 1800.2-2017 auto 10.5.1.1 +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_CONTAINER + local process m_drain_proc[uvm_object]; +`else + local 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 -- NODOCS -- new + // + // Creates a new objection instance. Accesses the command line + // argument +UVM_OBJECTION_TRACE to turn tracing on for + // all objection objects. + + // @uvm-ieee 1800.2-2017 auto 10.5.1.2 + 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 setting + clp = uvm_cmdline_processor::get_inst(); + if(clp.get_arg_matches("+UVM_OBJECTION_TRACE", trace_args)) begin + m_trace_mode=1; + end + m_objections.push_back(this); + endfunction + + + // Function -- NODOCS -- 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 updates + + function void m_report(uvm_object obj, uvm_object source_obj, string description, int count, string action); + 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; + + 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 begin + int 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)) begin + if(sname[cpath] == ".") last_dot = cpath; + cpath++; + end + + if(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); + end + endfunction + + + // 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)) begin + obj = comp.get_parent(); + end + else if ($cast(seq, obj)) begin + obj = seq.get_sequencer(); + end + else + obj = 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) begin + obj = m_get_parent(obj); + if(raise) + m_raise(obj, source_obj, description, count); + else + m_drop(obj, source_obj, description, count, in_top_thread); + end + endfunction + + + // Group -- NODOCS -- Objection Control + + + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.2 + 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; + end + + m_prop_mode = prop_mode; + endfunction : set_propagate_mode + + + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.1 + function bit get_propagate_mode(); + return m_prop_mode; + endfunction : get_propagate_mode + + // Function -- NODOCS -- 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, + // , 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 virtual method is called, which calls the + // method for all of the components up the + // hierarchy. + // + + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.3 + 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_raise + + function 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 0 + if (count == 0) + return; + + if (m_total_count.exists(obj)) + m_total_count[obj] += count; + else + m_total_count[obj] = count; + + if (source_obj==obj) begin + if (m_source_count.exists(obj)) + m_source_count[obj] += count; + else + m_source_count[obj] = count; + end + + if (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 list + idx = 0; + while (idx < m_scheduled_list.size()) begin + if ((m_scheduled_list[idx].obj == obj) && + (m_scheduled_list[idx].objection == this)) begin + // Caught it before the drain was forked + ctxt = m_scheduled_list[idx]; + m_scheduled_list.delete(idx); + break; + end + idx++; + end + + // If it's not there, go through the forked list + if (ctxt == null) begin + idx = 0; + while (idx < m_forked_list.size()) begin + if (m_forked_list[idx].obj == obj) begin + // Caught it after the drain was forked, + // but before the fork started + ctxt = m_forked_list[idx]; + m_forked_list.delete(idx); + m_scheduled_contexts.delete(ctxt.obj); + break; + end + idx++; + end + end + + // If it's not there, go through the forked contexts + if (ctxt == null) begin + if (m_forked_contexts.exists(obj)) begin + // Caught it with the forked drain running + ctxt = m_forked_contexts[obj]; + m_forked_contexts.delete(obj); + // Kill the drain +`ifndef UVM_USE_PROCESS_CONTAINER + m_drain_proc[obj].kill(); + m_drain_proc.delete(obj); +`else + m_drain_proc[obj].p.kill(); + m_drain_proc.delete(obj); +`endif + + end + end + + if (ctxt == null) begin + // If there were no drains, just propagate as usual + + if (!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); + end + else begin + // Otherwise we need to determine what exactly happened + int 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 changed + if (diff_count > 0) begin + // we're looking at an increase in the total + if (!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); + end + else 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); + end + end + + // Cleanup + ctxt.clear(); + m_context_pool.push_back(ctxt); + end + + endfunction + + + // Function -- NODOCS -- 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, + // , 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 virtual method is called, which calls the + // 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 + // . 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 + // 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 virtual method is called, which calls the + // 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 , 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. + + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.4 + 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_drop + + function 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 0 + if (count == 0) + return; + + if (!m_total_count.exists(obj) || (count > m_total_count[obj])) begin + if(m_cleared) + return; + uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(), + "\" attempted to drop objection '",this.get_name(),"' count below zero"}); + return; + end + + if (obj == source_obj) begin + if (!m_source_count.exists(obj) || (count > m_source_count[obj])) begin + if(m_cleared) + return; + uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(), + "\" attempted to drop objection '",this.get_name(),"' count below zero"}); + return; + end + m_source_count[obj] -= count; + end + + m_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 fork + if (m_total_count[obj] != 0) begin + if (!m_prop_mode && obj != m_top) + m_drop(m_top,source_obj,description, count, in_top_thread); + else if (obj != m_top) begin + this.m_propagate(obj, source_obj, description, count, 0, in_top_thread); + end + + end + else begin + uvm_objection_context_object ctxt; + if (m_context_pool.size()) + ctxt = m_context_pool.pop_front(); + else + ctxt = 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 + + + + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.5 + virtual function void clear(uvm_object obj=null); + string name; + int idx; + + if (obj==null) + obj=m_top; + name = obj.get_full_name(); + if (name == "") + name = "uvm_top"; + else + name = 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 queue + idx = 0; + while (idx < m_scheduled_list.size()) begin + if (m_scheduled_list[idx].objection == this) begin + m_scheduled_list[idx].clear(); + m_context_pool.push_back(m_scheduled_list[idx]); + m_scheduled_list.delete(idx); + end + else begin + idx++; + end + end + + // Scheduled contexts and m_forked_lists have duplicate + // entries... clear out one, free the other. + m_scheduled_contexts.delete(); + while (m_forked_list.size()) begin + m_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 process + foreach (m_forked_contexts[o]) begin +`ifndef UVM_USE_PROCESS_CONTAINER + m_drain_proc[o].kill(); + m_drain_proc.delete(o); +`else + m_drain_proc[o].p.kill(); + m_drain_proc.delete(o); +`endif + + m_forked_contexts[o].clear(); + m_context_pool.push_back(m_forked_contexts[o]); + m_forked_contexts.delete(o); + end + + m_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 non + static task m_execute_scheduled_forks(); + while(1) begin + wait(m_scheduled_list.size() != 0); + if(m_scheduled_list.size() != 0) begin + uvm_objection_context_object c; + // Save off the context before the fork + c = 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 list + c.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 : guard + automatic uvm_objection objection = c.objection; + begin + // Check to maike sure re-raise didn't empty the fifo + if (objection.m_forked_list.size() > 0) begin + uvm_objection_context_object ctxt; + ctxt = objection.m_forked_list.pop_front(); + // Clear it out of scheduled + objection.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_CONTAINER + objection.m_drain_proc[ctxt.obj] = process::self(); +`else + begin + process_container_c c = new(process::self()); + objection.m_drain_proc[ctxt.obj]=c; + end +`endif + // Execute the forked drain + objection.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 reuse + m_context_pool.push_back(ctxt); + end + end + join_none : guard + end + end + endtask + + + // m_forked_drain + // ------------- + + task m_forked_drain (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1, + int in_top_thread=0); + + 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 complete + wait fork; + + /* NOT NEEDED - Any raise would have killed us! + if(!m_total_count.exists(obj)) + diff_count = -count; + else + diff_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 process + static function void m_init_objections(); + fork + uvm_objection::m_execute_scheduled_forks(); + join_none + endfunction + + // Function -- NODOCS -- 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)? + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.7 + function void set_drain_time (uvm_object obj=null, time drain); + if (obj==null) + obj = m_top; + m_drain_time[obj] = drain; + endfunction + + + //---------------------- + // Group -- NODOCS -- Callback Hooks + //---------------------- + + // Function -- NODOCS -- raised + // + // Objection callback that is called when a has reached ~obj~. + // The default implementation calls . + + // @uvm-ieee 1800.2-2017 auto 10.5.1.4.1 + 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 -- NODOCS -- dropped + // + // Objection callback that is called when a has reached ~obj~. + // The default implementation calls . + + // @uvm-ieee 1800.2-2017 auto 10.5.1.4.2 + 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 -- NODOCS -- all_dropped + // + // Objection callback that is called when a 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-ieee 1800.2-2017 auto 10.5.1.4.3 + 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 -- NODOCS -- Objection Status + //------------------------ + + // Function -- NODOCS -- get_objectors + // + // Returns the current list of objecting objects (objects that + // raised an objection but have not dropped it). + + // @uvm-ieee 1800.2-2017 auto 10.5.1.5.1 + function void get_objectors(ref uvm_object list[$]); + list.delete(); + foreach (m_source_count[obj]) list.push_back(obj); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 10.5.1.5.2 + task wait_for(uvm_objection_event objt_event, uvm_object obj=null); + + if (obj==null) + obj = m_top; + + if (!m_events.exists(obj)) begin + m_events[obj] = new; + end + + m_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); + endcase + + m_events[obj].waiters--; + + if (m_events[obj].waiters == 0) + m_events.delete(obj); + + endtask + + + task 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); + else + wait (m_total_count.exists(obj) && m_total_count[obj] == count); + endtask + + + // Function -- NODOCS -- get_objection_count + // + // Returns the current number of objections raised by the given ~object~. + + // @uvm-ieee 1800.2-2017 auto 10.5.1.5.3 + 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 -- NODOCS -- get_objection_total + // + // Returns the current number of objections raised by the given ~object~ + // and all descendants. + + // @uvm-ieee 1800.2-2017 auto 10.5.1.5.4 + function int get_objection_total (uvm_object obj=null); + + if (obj==null) + obj = m_top; + + if (!m_total_count.exists(obj)) + return 0; + else + return m_total_count[obj]; + + endfunction + + + // Function -- NODOCS -- get_drain_time + // + // Returns the current drain time set for the given ~object~ (default: 0 ns). + + // @uvm-ieee 1800.2-2017 auto 10.5.1.3.6 + 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_objections + + protected 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]) begin + uvm_object theobj = o; + if ( m_total_count[o] > 0) + list[theobj.get_full_name()] = theobj; + end + + if (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 begin + + curr_obj = list[curr_obj_name]; + + // determine depth + depth=0; + foreach (curr_obj_name[i]) + if (curr_obj_name[i] == ".") + depth++; + + // determine leaf name + name = curr_obj_name; + for (int i=curr_obj_name.len()-1;i >= 0; i--) + if (curr_obj_name[i] == ".") begin + name = curr_obj_name.substr(i+1,curr_obj_name.len()-1); + break; + end + if (curr_obj_name == "") + name = "uvm_top"; + else + depth++; + + // print it + s = {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; + + endfunction + + + function string convert2string(); + return m_display_objections(m_top,1); + endfunction + + + // Function -- NODOCS -- display_objections + // + // Displays objection information about the given ~object~. If ~object~ is + // not specified or ~null~, the implicit top-level component, , 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; +`ifdef VERILATOR + static function uvm_objection type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction +`endif + static function type_id get_type(); + return type_id::get(); + endfunction + + function uvm_object create (string name=""); + uvm_objection tmp = new(name); + return tmp; + endfunction + + virtual function string get_type_name (); + return "uvm_objection"; + endfunction + + function 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; + endfunction + +endclass + +// TODO: change to plusarg +//`define UVM_DEFAULT_TIMEOUT 9200s + +typedef class uvm_cmdline_processor; + + +`ifdef UVM_ENABLE_DEPRECATED_API +//------------------------------------------------------------------------------ +// +// 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 phasing + local 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 or + // . + + 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))) begin + uvm_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 }); + end + endfunction + + // 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(); + endfunction + + function uvm_object create (string name=""); + uvm_test_done_objection tmp = new(name); + return tmp; + endfunction + + virtual function string get_type_name (); + return "uvm_test_done"; + endfunction + + static function uvm_test_done_objection get(); + if(m_inst == null) + `ifdef VERILATOR + m_inst = uvm_test_done_objection::type_id_create("run"); + `else + m_inst = uvm_test_done_objection::type_id::create("run"); + `endif + return m_inst; + endfunction + +endclass +`endif // UVM_ENABLE_DEPRECATED_API + + +// Have a pool of context objects to use +class 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 objects + function void clear(); + obj = null; + source_obj = null; + description = ""; + count = 0; + objection = null; + endfunction : clear +endclass + +// Typedef - Exists for backwards compat +typedef uvm_objection uvm_callbacks_objection; + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- 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 +//| end + + +// @uvm-ieee 1800.2-2017 auto 10.5.2.1 +class uvm_objection_callback extends uvm_callback; + function new(string name); + super.new(name); + endfunction + + // Function -- NODOCS -- raised + // + // Objection raised callback function. Called by . + + // @uvm-ieee 1800.2-2017 auto 10.5.2.2.1 + virtual function void raised (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endfunction + + // Function -- NODOCS -- dropped + // + // Objection dropped callback function. Called by . + + // @uvm-ieee 1800.2-2017 auto 10.5.2.2.2 + virtual function void dropped (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endfunction + + // Function -- NODOCS -- all_dropped + // + // Objection all_dropped callback function. Called by . + + // @uvm-ieee 1800.2-2017 auto 10.5.2.2.3 + virtual task all_dropped (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endtask + +endclass + + +`endif diff --git a/test_regress/t/t_uvm/base/uvm_packer.svh b/test_regress/t/t_uvm/base/uvm_packer.svh new file mode 100644 index 0000000000..656dc757d2 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_packer.svh @@ -0,0 +1,1193 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2018 Qualcomm, Inc. +// Copyright 2014 Intel Corporation +// Copyright 2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, 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_packer +// +// The uvm_packer class provides a policy object for packing and unpacking +// uvm_objects. The policies determine how packing and unpacking should be done. +// Packing an object causes the object to be placed into a bit (byte or int) +// array. If the `uvm_field_* macro are used to implement pack and unpack, +// by default no metadata information is stored for the packing of dynamic +// objects (strings, arrays, class objects). +// +//------------------------------------------------------------------------------- + +typedef bit signed [(`UVM_PACKER_MAX_BYTES*8)-1:0] uvm_pack_bitstream_t; + +// Class: uvm_packer +// Implementation of uvm_packer, as defined in section +// 16.5.1 of 1800.2-2017 + +// @uvm-ieee 1800.2-2017 auto 16.5.1 +class uvm_packer extends uvm_policy; + + // @uvm-ieee 1800.2-2017 auto 16.5.2.3 + `uvm_object_utils(uvm_packer) + + uvm_factory m_factory; + local uvm_object m_object_references[int]; + + + // Function: set_packed_* + // Implementation of P1800.2 16.5.3.1 + // + // The LRM specifies the set_packed_* methods as being + // signed, whereas the methods are specified + // as unsigned. This is being tracked in Mantis 6423. + // + // The reference implementation has implemented these methods + // as unsigned so as to remain consistent. + // + //| virtual function void set_packed_bits( ref bit unsigned stream[] ); + //| virtual function void set_packed_bytes( ref byte unsigned stream[] ); + //| virtual function void set_packed_ints( ref int unsigned stream[] ); + //| virtual function void set_packed_longints( ref longint unsigned stream[] ); + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 16.5.3.1 + extern virtual function void set_packed_bits (ref bit unsigned stream[]); + + // @uvm-ieee 1800.2-2017 auto 16.5.3.1 + extern virtual function void set_packed_bytes (ref byte unsigned stream[]); + + // @uvm-ieee 1800.2-2017 auto 16.5.3.1 + extern virtual function void set_packed_ints (ref int unsigned stream[]); + + // @uvm-ieee 1800.2-2017 auto 16.5.3.1 + extern virtual function void set_packed_longints (ref longint unsigned stream[]); + + // Function: get_packed_* + // Implementation of P1800.2 16.5.3.2 + // + // The LRM specifies the get_packed_* methods as being + // signed, whereas the methods are specified + // as unsigned. This is being tracked in Mantis 6423. + // + // The reference implementation has implemented these methods + // as unsigned so as to remain consistent. + // + //| virtual function void get_packed_bits( ref bit unsigned stream[] ); + //| virtual function void get_packed_bytes( ref byte unsigned stream[] ); + //| virtual function void get_packed_ints( ref int unsigned stream[] ); + //| virtual function void get_packed_longints( ref longint unsigned stream[] ); + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 16.5.3.2 + extern virtual function void get_packed_bits (ref bit unsigned stream[]); + + // @uvm-ieee 1800.2-2017 auto 16.5.3.2 + extern virtual function void get_packed_bytes (ref byte unsigned stream[]); + + // @uvm-ieee 1800.2-2017 auto 16.5.3.2 + extern virtual function void get_packed_ints (ref int unsigned stream[]); + + // @uvm-ieee 1800.2-2017 auto 16.5.3.2 + extern virtual function void get_packed_longints (ref longint unsigned stream[]); + + //----------------// + // Group -- NODOCS -- Packing // + //----------------// + + // @uvm-ieee 1800.2-2017 auto 16.5.2.4 + static function void set_default (uvm_packer packer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_packer(packer) ; + endfunction + + // @uvm-ieee 1800.2-2017 auto 16.5.2.5 + static function uvm_packer get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_packer() ; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 16.5.2.2 + extern virtual function void flush (); + // Function -- NODOCS -- pack_field + // + // Packs an integral value (less than or equal to 4096 bits) into the + // packed array. ~size~ is the number of bits of ~value~ to pack. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.8 + extern virtual function void pack_field (uvm_bitstream_t value, int size); + + + // Function -- NODOCS -- pack_field_int + // + // Packs the integral value (less than or equal to 64 bits) into the + // pack array. The ~size~ is the number of bits to pack, usually obtained by + // ~$bits~. This optimized version of is useful for sizes up + // to 64 bits. + + // @uvm-ieee 1800.2-2017 auto 16.5.2.1 + extern function new(string name=""); + + // @uvm-ieee 1800.2-2017 auto 16.5.4.9 + extern virtual function void pack_field_int (uvm_integral_t value, int size); + + + // @uvm-ieee 1800.2-2017 auto 16.5.4.1 + extern virtual function void pack_bits(ref bit value[], input int size = -1); + + + // @uvm-ieee 1800.2-2017 auto 16.5.4.10 + extern virtual function void pack_bytes(ref byte value[], input int size = -1); + + + // @uvm-ieee 1800.2-2017 auto 16.5.4.11 + extern virtual function void pack_ints(ref int value[], input int size = -1); + + // recursion functions + + + + // Function -- NODOCS -- pack_string + // + // Packs a string value into the pack array. + // + // When the metadata flag is set, the packed string is terminated by a ~null~ + // character to mark the end of the string. + // + // This is useful for mixed language communication where unpacking may occur + // outside of SystemVerilog UVM. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.5 + extern virtual function void pack_string (string value); + + + // Function -- NODOCS -- pack_time + // + // Packs a time ~value~ as 64 bits into the pack array. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.6 + extern virtual function void pack_time (time value); + + + // Function -- NODOCS -- pack_real + // + // Packs a real ~value~ as 64 bits into the pack array. + // + // The real ~value~ is converted to a 6-bit scalar value using the function + // $real2bits before it is packed into the array. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.7 + extern virtual function void pack_real (real value); + + + // Function -- NODOCS -- pack_object + // + // Packs an object value into the pack array. + // + // A 4-bit header is inserted ahead of the string to indicate the number of + // bits that was packed. If a ~null~ object was packed, then this header will + // be 0. + // + // This is useful for mixed-language communication where unpacking may occur + // outside of SystemVerilog UVM. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.2 + extern virtual function void pack_object (uvm_object value); + + extern virtual function void pack_object_with_meta (uvm_object value); + + extern virtual function void pack_object_wrapper (uvm_object_wrapper value); + + + //------------------// + // Group -- NODOCS -- Unpacking // + //------------------// + + // Function -- NODOCS -- is_null + // + // This method is used during unpack operations to peek at the next 4-bit + // chunk of the pack data and determine if it is 0. + // + // If the next four bits are all 0, then the return value is a 1; otherwise + // it is 0. + // + // This is useful when unpacking objects, to decide whether a new object + // needs to be allocated or not. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.3 + extern virtual function bit is_null (); + + + extern virtual function bit is_object_wrapper(); + // Function -- NODOCS -- unpack_field + // + // Unpacks bits from the pack array and returns the bit-stream that was + // unpacked. ~size~ is the number of bits to unpack; the maximum is 4096 bits. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.16 + extern virtual function uvm_bitstream_t unpack_field (int size); + + // Function -- NODOCS -- unpack_field_int + // + // Unpacks bits from the pack array and returns the bit-stream that was + // unpacked. + // + // ~size~ is the number of bits to unpack; the maximum is 64 bits. + // This is a more efficient variant than unpack_field when unpacking into + // smaller vectors. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.17 + extern virtual function uvm_integral_t unpack_field_int (int size); + + + // @uvm-ieee 1800.2-2017 auto 16.5.4.18 + extern virtual function void unpack_bits(ref bit value[], input int size = -1); + + + // @uvm-ieee 1800.2-2017 auto 16.5.4.19 + extern virtual function void unpack_bytes(ref byte value[], input int size = -1); + + + // @uvm-ieee 1800.2-2017 auto 16.5.4.12 + extern virtual function void unpack_ints(ref int value[], input int size = -1); + + + // Function -- NODOCS -- unpack_string + // + // Unpacks a string. + // + // num_chars bytes are unpacked into a string. If num_chars is -1 then + // unpacking stops on at the first ~null~ character that is encountered. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.13 + extern virtual function string unpack_string (); + + + // Function -- NODOCS -- unpack_time + // + // Unpacks the next 64 bits of the pack array and places them into a + // time variable. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.14 + extern virtual function time unpack_time (); + + + // Function -- NODOCS -- unpack_real + // + // Unpacks the next 64 bits of the pack array and places them into a + // real variable. + // + // The 64 bits of packed data are converted to a real using the $bits2real + // system function. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.15 + extern virtual function real unpack_real (); + + + // Function -- NODOCS -- unpack_object + // + // Unpacks an object and stores the result into ~value~. + // + // ~value~ must be an allocated object that has enough space for the data + // being unpacked. The first four bits of packed data are used to determine + // if a ~null~ object was packed into the array. + // + // The function can be used to peek at the next four bits in + // the pack array before calling this method. + + // @uvm-ieee 1800.2-2017 auto 16.5.4.4 + extern virtual function void unpack_object (uvm_object value); + + extern virtual function void unpack_object_with_meta (inout uvm_object value); + + extern virtual function uvm_object_wrapper unpack_object_wrapper(); + + + // Function -- NODOCS -- get_packed_size + // + // Returns the number of bits that were packed. + + // @uvm-ieee 1800.2-2017 auto 16.5.3.3 + extern virtual function int get_packed_size(); + + + //------------------// + // Group -- NODOCS -- Variables // + //------------------// + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- physical + // + // This bit provides a filtering mechanism for fields. + // + // The and physical settings allow an object to distinguish between + // two different classes of fields. It is up to you, in the + // and methods, to test the + // setting of this field if you want to use it as a filter. + + bit physical = 1; + + + // Variable -- NODOCS -- abstract + // + // This bit provides a filtering mechanism for fields. + // + // The abstract and physical settings allow an object to distinguish between + // two different classes of fields. It is up to you, in the + // and routines, to test the + // setting of this field if you want to use it as a filter. + + bit abstract; + + + // Variable -- NODOCS -- big_endian + // + // This bit determines the order that integral data is packed (using + // , , , or ) and how the + // data is unpacked from the pack array (using , + // , , or ). When the bit is set, + // data is associated msb to lsb; otherwise, it is associated lsb to msb. + // + // The following code illustrates how data can be associated msb to lsb and + // lsb to msb: + // + //| class mydata extends uvm_object; + //| + //| logic[15:0] value = 'h1234; + //| + //| function void do_pack (uvm_packer packer); + //| packer.pack_field_int(value, 16); + //| endfunction + //| + //| function void do_unpack (uvm_packer packer); + //| value = packer.unpack_field_int(16); + //| endfunction + //| endclass + //| + //| mydata d = new; + //| bit bits[]; + //| + //| initial begin + //| d.pack(bits); // 'b0001001000110100 + //| uvm_default_packer.big_endian = 0; + //| d.pack(bits); // 'b0010110001001000 + //| end + + bit big_endian = 0; +`endif + + // variables and methods primarily for internal use + + static bit bitstream[]; // local bits for (un)pack_bytes + static bit fabitstream[]; // field automation bits for (un)pack_bytes + int m_pack_iter; // Used to track the bit of the next pack + int m_unpack_iter; // Used to track the bit of the next unpack + + bit reverse_order; //flip the bit order around + byte byte_size = 8; //set up bytesize for endianess + int word_size = 16; //set up worksize for endianess + bit nopack; //only count packable bits + + uvm_pack_bitstream_t m_bits; + + +`ifdef UVM_ENABLE_DEPRECATED_API + extern virtual function bit unsigned get_bit (int unsigned index); + extern virtual function byte unsigned get_byte (int unsigned index); + extern virtual function int unsigned get_int (int unsigned index); + + extern virtual function void get_bits (ref bit unsigned bits[]); + extern virtual function void get_bytes(ref byte unsigned bytes[]); + extern virtual function void get_ints (ref int unsigned ints[]); + + extern virtual function void put_bits (ref bit unsigned bitstream[]); + extern virtual function void put_bytes(ref byte unsigned bytestream[]); + extern virtual function void put_ints (ref int unsigned intstream[]); + + extern virtual function void set_packed_size(); +`endif + + extern function void index_error(int index, string id, int sz); + extern function bit enough_bits(int needed, string id); + +`ifdef UVM_ENABLE_DEPRECATED_API + extern function void reset(); +`endif + +endclass + + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// NOTE- max size limited to BITSTREAM bits parameter (default: 4096) + + +// index_ok +// -------- + +function void uvm_packer::index_error(int index, string id, int sz); + uvm_report_error("PCKIDX", + $sformatf("index %0d for get_%0s too large; valid index range is 0-%0d.", + index,id,((m_pack_iter+sz-1)/sz)-1), UVM_NONE); +endfunction + + +// enough_bits +// ----------- + +function bit uvm_packer::enough_bits(int needed, string id); + if ((m_pack_iter - m_unpack_iter) < needed) begin + uvm_report_error("PCKSZ", + $sformatf("%0d bits needed to unpack %0s, yet only %0d available.", + needed, id, (m_pack_iter - m_unpack_iter)), UVM_NONE); + return 0; + end + return 1; +endfunction + + +// get_packed_size +// --------------- + +function int uvm_packer::get_packed_size(); + return m_pack_iter - m_unpack_iter; +endfunction + + +`ifdef UVM_ENABLE_DEPRECATED_API +// set_packed_size +// --------------- + +function void uvm_packer::set_packed_size(); + /* doesn't actually do anything now */ +endfunction + +// reset +// ----- + +function void uvm_packer::reset(); + flush(); +endfunction + +function void uvm_packer::get_bits( ref bit bits [] ); get_packed_bits(bits); endfunction +function void uvm_packer::get_bytes( ref byte unsigned bytes [] ); get_packed_bytes(bytes); endfunction +function void uvm_packer::get_ints( ref int unsigned ints [] ); get_packed_ints(ints); endfunction +`endif + +function void uvm_packer::flush(); + // The iterators are spaced 64b from the beginning, enough to store + // the iterators during get_packed_* and retrieve them during + // set_packed_*. Without this, set_packed_[byte|int|longint] will + // move the iterators too far. + m_pack_iter = 64; + m_unpack_iter = 64; + m_bits = 0; + m_object_references.delete(); + m_object_references[0] = null; + m_factory = null; + super.flush(); +endfunction : flush + +// get_packed_bits +// -------- + +function void uvm_packer::get_packed_bits(ref bit unsigned stream[]); + stream = new[m_pack_iter]; + m_bits[31:0] = m_pack_iter; /* Reserved bits */ + m_bits[63:32] = m_unpack_iter; /* Reserved bits */ + for (int i=0;i> ($bits(T)-(m_pack_iter%$bits(T)))); \ + if(big_endian) \ + v = {<<{v}}; \ + stream[i] = v; \ + end \ +endfunction +`else // !`ifdef UVM_ENABLE_DEPRECATED_API +`define M__UVM_GET_PACKED(T) \ +function void uvm_packer::get_packed_``T``s (ref T unsigned stream[] ); \ + int sz; \ + T v; \ + sz = (m_pack_iter + $high(v)) / $bits(T); \ + m_bits[31:0] = m_pack_iter; /* Reserved Bits */ \ + m_bits[63:32] = m_unpack_iter; /* Reserved Bits */ \ + stream = new[sz]; \ + foreach (stream[i]) begin \ + if (i != sz-1 || (m_pack_iter % $bits(T)) == 0) \ + v = m_bits[ i* $bits(T) +: $bits(T) ]; \ + else \ + v = m_bits[ i* $bits(T) +: $bits(T) ] & ({$bits(T){1'b1}} >> ($bits(T)-(m_pack_iter%$bits(T)))); \ + stream[i] = v; \ + end \ +endfunction +`endif // !`ifdef UVM_ENABLE_DEPRECATED_API + +`M__UVM_GET_PACKED(byte) +`M__UVM_GET_PACKED(int) +`M__UVM_GET_PACKED(longint) + +`undef M__UVM_GET_PACKED + +`ifdef UVM_ENABLE_DEPRECATED_API +function void uvm_packer::put_bits( ref bit bitstream [] ); set_packed_bits(bitstream); endfunction +function void uvm_packer::put_bytes( ref byte unsigned bytestream [] ); set_packed_bytes(bytestream); endfunction +function void uvm_packer::put_ints( ref int unsigned intstream [] ); set_packed_ints(intstream); endfunction +`endif + +// set_packed_bits +// -------- + +function void uvm_packer::set_packed_bits (ref bit stream []); + + int bit_size; + + bit_size = stream.size(); + +`ifdef UVM_ENABLE_DEPRECATED_API + if(big_endian) + for (int i=bit_size-1;i>=0;i--) + m_bits[i] = stream[i]; + else +`endif + for (int i=0;i= m_pack_iter) + index_error(index, "bit",1); + return m_bits[index]; +endfunction + + +// get_byte +// -------- + +function byte unsigned uvm_packer::get_byte(int unsigned index); + if (index >= (m_pack_iter+7)/8) + index_error(index, "byte",8); + return m_bits[index*8 +: 8]; +endfunction + + +// get_int +// ------- + +function int unsigned uvm_packer::get_int(int unsigned index); + if (index >= (m_pack_iter+31)/32) + index_error(index, "int",32); + return m_bits[(index*32) +: 32]; +endfunction +`endif + +// PACK + + +// pack_object +// --------- + +function void uvm_packer::pack_object(uvm_object value); + uvm_field_op field_op; + if (value == null ) begin + m_bits[m_pack_iter +: 4] = 0; + m_pack_iter += 4; + return ; + end + else begin + m_bits[m_pack_iter +: 4] = 4'hF; + m_pack_iter += 4; + end + + push_active_object(value); + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_PACK,this,value); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + value.do_pack(this); + end + field_op.m_recycle(); + void'(pop_active_object()); +endfunction + +// Function: pack_object_with_meta +// Packs ~obj~ into the packer data stream, such that +// it can be unpacked via an associated +// call. +// +// Unlike , the pack_object_with_meta method keeps track +// of what objects have already been packed in this call chain. The +// first time an object is passed to pack_object_with_meta after a +// call to , the object is assigned a unique id. Subsequent +// calls to pack_object_with_meta will only add the unique id to the +// stream. This allows structural information to be maintained through +// pack/unpack operations. +// +// Note: pack_object_with_meta is not compatible with +// and . The object can only be unpacked via +// . +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +function void uvm_packer::pack_object_with_meta(uvm_object value); + int reference_id; + foreach(m_object_references[i]) begin + if (m_object_references[i] == value) begin + pack_field_int(i,32); + return; + end + end + + // Size will always be >0 because 0 is the null + reference_id = m_object_references.size(); + pack_field_int(reference_id,32); + m_object_references[reference_id] = value; + pack_object_wrapper(value.get_object_type()); + + pack_object(value); +endfunction + + +function void uvm_packer::pack_object_wrapper(uvm_object_wrapper value); + string type_name; + if (value != null) begin + pack_string(value.get_type_name()); + end +endfunction +// pack_real +// --------- + +function void uvm_packer::pack_real(real value); + pack_field_int($realtobits(value), 64); +endfunction + + +// pack_time +// --------- + +function void uvm_packer::pack_time(time value); + pack_field_int(value, 64); + //m_bits[m_pack_iter +: 64] = value; this overwrites endian adjustments +endfunction + + +// pack_field +// ---------- + +function void uvm_packer::pack_field(uvm_bitstream_t value, int size); + for (int i=0; i value.size()) begin + `uvm_error("UVM/BASE/PACKER/BAD_SIZE", + $sformatf("pack_bits called with size '%0d', which exceeds value.size() of '%0d'", + size, + value.size())) + return; + end + + for (int i=0; i max_size) begin + `uvm_error("UVM/BASE/PACKER/BAD_SIZE", + $sformatf("pack_bytes called with size '%0d', which exceeds value size of '%0d'", + size, + max_size)) + return; + end + else begin + int idx_select; + + for (int i=0; i max_size) begin + `uvm_error("UVM/BASE/PACKER/BAD_SIZE", + $sformatf("pack_ints called with size '%0d', which exceeds value size of '%0d'", + size, + max_size)) + return; + end + else begin + int idx_select; + + for (int i=0; i. +// +// Unlike , the unpack_object_with_meta method keeps track +// of what objects have already been unpacked in this call chain. If the +// packed object was null, then ~value~ is set to null. Otherwise, if this +// is the first time the object's unique id +// has been encountered since a call to , +// then unpack_object_with_meta checks ~value~ to determine if it is the +// correct type. If it is not the correct type, or if ~value~ is null, +// then the packer shall create a new object instance for the unpack operation, +// using the data provided by . If ~value~ is of the +// correct type, then it is used as the object instance for the unpack operation. +// Subsequent calls to unpack_object_with_meta for this unique id shall +// simply set ~value~ to this object instance. +// +// Note: unpack_object_with_meta is not compatible with +// or . The object must have been packed via +// . +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 +function void uvm_packer::unpack_object_with_meta(inout uvm_object value); + int reference_id; + reference_id = unpack_field_int(32); + if (m_object_references.exists(reference_id)) begin + value = m_object_references[reference_id]; + return; + end + else begin + uvm_object_wrapper __wrapper = unpack_object_wrapper(); + if ((__wrapper != null) && + ((value == null) || (value.get_object_type() != __wrapper))) begin + value = __wrapper.create_object(""); + if (value == null) begin + value = __wrapper.create_component("",null); + end + end + end + m_object_references[reference_id] = value; + unpack_object(value); +endfunction + + +function uvm_object_wrapper uvm_packer::unpack_object_wrapper(); + string type_name; + type_name = unpack_string(); + if (m_factory == null) + m_factory = uvm_factory::get(); + if (m_factory.is_type_name_registered(type_name)) begin + return m_factory.find_wrapper_by_name(type_name); + end + return null; + +endfunction + +// unpack_real +// ----------- + +function real uvm_packer::unpack_real(); + if (enough_bits(64,"real")) begin + return $bitstoreal(unpack_field_int(64)); + end +endfunction + + +// unpack_time +// ----------- + +function time uvm_packer::unpack_time(); + if (enough_bits(64,"time")) begin + return unpack_field_int(64); + end +endfunction + + +// unpack_field +// ------------ + +function uvm_bitstream_t uvm_packer::unpack_field(int size); + unpack_field = 'b0; + if (enough_bits(size,"integral")) begin + m_unpack_iter += size; + for (int i=0; i max_size) begin + `uvm_error("UVM/BASE/PACKER/BAD_SIZE", + $sformatf("unpack_bytes called with size '%0d', which exceeds value size of '%0d'", + size, + value.size())) + return; + end + else begin + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + + for (int i=0; i max_size) begin + `uvm_error("UVM/BASE/PACKER/BAD_SIZE", + $sformatf("unpack_ints called with size '%0d', which exceeds value size of '%0d'", + size, + value.size())) + return; + end + else begin + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + + for (int i=0; i) in APIs. For those APIs that need to look +// up that phase in the graph, this is done automatically. + // @uvm-ieee 1800.2-2017 auto 9.3.1.2 class uvm_phase extends uvm_object; //`uvm_object_utils(uvm_phase) - //UVM `uvm_register_cb(uvm_phase, uvm_phase_cb) + `uvm_register_cb(uvm_phase, uvm_phase_cb) //-------------------- // Group -- NODOCS -- Construction //-------------------- - + // @uvm-ieee 1800.2-2017 auto 9.3.1.3.1 extern function new(string name="uvm_phase", @@ -119,6 +208,213 @@ class uvm_phase extends uvm_object; // @uvm-ieee 1800.2-2017 auto 9.3.1.4.7 extern function bit is_after(uvm_phase phase); + + //----------------- + // Group -- NODOCS -- Callbacks + //----------------- + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.5.1 + virtual function void exec_func(uvm_component comp, uvm_phase phase); endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.5.2 + virtual task exec_task(uvm_component comp, uvm_phase phase); endtask + + + + //---------------- + // Group -- NODOCS -- Schedule + //---------------- + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.1 + extern function void add(uvm_phase phase, + uvm_phase with_phase=null, + uvm_phase after_phase=null, + uvm_phase before_phase=null, + uvm_phase start_with_phase=null, + uvm_phase end_with_phase=null + ); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.2 + extern function uvm_phase get_parent(); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.3 + extern virtual function string get_full_name(); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.4 + extern function uvm_phase get_schedule(bit hier = 0); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.5 + extern function string get_schedule_name(bit hier = 0); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.6 + extern function uvm_domain get_domain(); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.7 + extern function uvm_phase get_imp(); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.8 + extern function string get_domain_name(); + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.9 + extern function void get_adjacent_predecessor_nodes(ref uvm_phase pred[]); + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.6.10 + extern function void get_adjacent_successor_nodes(ref uvm_phase succ[]); + + //----------------------- + // Group -- NODOCS -- Phase Done Objection + //----------------------- + // + // Task-based phase nodes within the phasing graph provide a + // based interface for prolonging the execution of the phase. All other + // phase types do not contain an objection, and will report a fatal error + // if the user attempts to ~raise~, ~drop~, or ~get_objection_count~. + + // Function- m_report_null_objection + // Simplifies the reporting of ~null~ objection errors + extern function void m_report_null_objection(uvm_object obj, + string description, + int count, + string action); + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.7.2 + extern virtual function void raise_objection (uvm_object obj, + string description="", + int count=1); + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.7.3 + extern virtual function void drop_objection (uvm_object obj, + string description="", + int count=1); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.7.4 + extern virtual function int get_objection_count( uvm_object obj=null ); + + //----------------------- + // Group -- NODOCS -- Synchronization + //----------------------- + // The functions 'sync' and 'unsync' add soft sync relationships between nodes + // + // Summary of usage: + //| my_phase.sync(.target(domain) + //| [,.phase(phase)[,.with_phase(phase)]]); + //| my_phase.unsync(.target(domain) + //| [,.phase(phase)[,.with_phase(phase)]]); + // + // Components in different schedule domains can be phased independently or in sync + // with each other. An API is provided to specify synchronization rules between any + // two domains. Synchronization can be done at any of three levels: + // + // - the domain's whole phase schedule can be synchronized + // - a phase can be specified, to sync that phase with a matching counterpart + // - or a more detailed arbitrary synchronization between any two phases + // + // Each kind of synchronization causes the same underlying data structures to + // be managed. Like other APIs, we use the parameter dot-notation to set + // optional parameters. + // + // When a domain is synced with another domain, all of the matching phases in + // the two domains get a 'with' relationship between them. Likewise, if a domain + // is unsynched, all of the matching phases that have a 'with' relationship have + // the dependency removed. It is possible to sync two domains and then just + // remove a single phase from the dependency relationship by unsyncing just + // the one phase. + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.8.1 + extern function void sync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.8.2 + extern function void unsync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.8.3 + extern task wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ); + + + //--------------- + // Group -- NODOCS -- Jumping + //--------------- + + // Force phases to jump forward or backward in a schedule + // + // A phasing domain can execute a jump from its current phase to any other. + // A jump passes phasing control in the current domain from the current phase + // to a target phase. There are two kinds of jump scope: + // + // - local jump to another phase within the current schedule, back- or forwards + // - global jump of all domains together, either to a point in the master + // schedule outwith the current schedule, or by calling jump_all() + // + // A jump preserves the existing soft synchronization, so the domain that is + // ahead of schedule relative to another synchronized domain, as a result of + // a jump in either domain, will await the domain that is behind schedule. + // + // *Note*: A jump out of the local schedule causes other schedules that have + // the jump node in their schedule to jump as well. In some cases, it is + // desirable to jump to a local phase in the schedule but to have all + // schedules that share that phase to jump as well. In that situation, the + // jump_all static function should be used. This function causes all schedules + // that share a phase to jump to that phase. + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.9.1 + extern function void jump(uvm_phase phase); + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.9.2 + extern function void set_jump_phase(uvm_phase phase) ; + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.9.3 + extern function void end_prematurely() ; + + // Function- jump_all + // + // Make all schedules jump to a specified ~phase~, even if the jump target is local. + // The jump happens to all phase schedules that contain the jump-to ~phase~, + // i.e. a global jump. + // + extern static function void jump_all(uvm_phase phase); + + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.9.4 + extern function uvm_phase get_jump_target(); + + + //-------------------------- // Internal - Implementation //-------------------------- @@ -149,14 +445,14 @@ class uvm_phase extends uvm_object; // Implementation - Callbacks //--------------------------- // Provide the required component traversal behavior. Called by execute() -//UVM virtual function void traverse(uvm_component comp, -//UVM uvm_phase phase, -//UVM uvm_phase_state state); -//UVM endfunction -//UVM // Provide the required per-component execution flow. Called by traverse() -//UVM virtual function void execute(uvm_component comp, -//UVM uvm_phase phase); -//UVM endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + endfunction + // Provide the required per-component execution flow. Called by traverse() + virtual function void execute(uvm_component comp, + uvm_phase phase); + endfunction // Implementation - Schedule //-------------------------- @@ -165,66 +461,66 @@ class uvm_phase extends uvm_object; protected uvm_phase m_end_node; // Track the currently executing real task phases (used for debug) static protected bit m_executing_phases[uvm_phase]; -//UVM function uvm_phase get_begin_node(); if (m_imp != null) return this; return null; endfunction -//UVM function uvm_phase get_end_node(); return m_end_node; endfunction + function uvm_phase get_begin_node(); if (m_imp != null) return this; return null; endfunction + function uvm_phase get_end_node(); return m_end_node; endfunction // Implementation - Synchronization //--------------------------------- local uvm_phase m_sync[$]; // schedule instance to which we are synced -//UVM `ifdef UVM_ENABLE_DEPRECATED_API -//UVM // In order to avoid raciness during static initialization, -//UVM // the creation of the "phase done" objection has been -//UVM // delayed until the first call to get_objection(), and all -//UVM // internal APIs have been updated to call get_objection() instead -//UVM // of referring to phase_done directly. -//UVM // -//UVM // So as to avoid potential null handle dereferences in user code -//UVM // which was accessing the phase_done variable directly, the variable -//UVM // was renamed, and made local. This takes a difficult to debug -//UVM // run-time error, and converts it into an easy to catch compile-time -//UVM // error. -//UVM // -//UVM // Code which is broken due to the protection of phase_done should be -//UVM // refactored to use the get_objection() method. Note that this also -//UVM // opens the door to virtual get_objection() code, as described in -//UVM // https://accellera.mantishub.io/view.php?id=6260 -//UVM uvm_objection phase_done; -//UVM `else // !`ifdef UVM_ENABLE_DEPRECATED_API -//UVM local uvm_objection phase_done; -//UVM `endif - +`ifdef UVM_ENABLE_DEPRECATED_API + // In order to avoid raciness during static initialization, + // the creation of the "phase done" objection has been + // delayed until the first call to get_objection(), and all + // internal APIs have been updated to call get_objection() instead + // of referring to phase_done directly. + // + // So as to avoid potential null handle dereferences in user code + // which was accessing the phase_done variable directly, the variable + // was renamed, and made local. This takes a difficult to debug + // run-time error, and converts it into an easy to catch compile-time + // error. + // + // Code which is broken due to the protection of phase_done should be + // refactored to use the get_objection() method. Note that this also + // opens the door to virtual get_objection() code, as described in + // https://accellera.mantishub.io/view.php?id=6260 + uvm_objection phase_done; +`else // !`ifdef UVM_ENABLE_DEPRECATED_API + local uvm_objection phase_done; +`endif + local int unsigned m_ready_to_end_count; -//UVM function int unsigned get_ready_to_end_count(); -//UVM return m_ready_to_end_count; -//UVM endfunction -//UVM -//UVM extern local function void get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); -//UVM extern local task m_wait_for_pred(); + function int unsigned get_ready_to_end_count(); + return m_ready_to_end_count; + endfunction + + extern local function void get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); + extern local task m_wait_for_pred(); // Implementation - Jumping //------------------------- -//UVM local bit m_jump_bkwd; -//UVM local bit m_jump_fwd; -//UVM local uvm_phase m_jump_phase; -//UVM local bit m_premature_end; -//UVM extern function void clear(uvm_phase_state state = UVM_PHASE_DORMANT); -//UVM extern function void clear_successors( -//UVM uvm_phase_state state = UVM_PHASE_DORMANT, -//UVM uvm_phase end_state=null); + local bit m_jump_bkwd; + local bit m_jump_fwd; + local uvm_phase m_jump_phase; + local bit m_premature_end; + extern function void clear(uvm_phase_state state = UVM_PHASE_DORMANT); + extern function void clear_successors( + uvm_phase_state state = UVM_PHASE_DORMANT, + uvm_phase end_state=null); // Implementation - Overall Control //--------------------------------- local static mailbox #(uvm_phase) m_phase_hopper = new(); -//UVM extern static task m_run_phases(); -//UVM extern local task execute_phase(); -//UVM extern local function void m_terminate_phase(); -//UVM extern local function void m_print_termination_state(); -//UVM extern local task wait_for_self_and_siblings_to_drop(); -//UVM extern function void kill(); -//UVM extern function void kill_successors(); + extern static task m_run_phases(); + extern local task execute_phase(); + extern local function void m_terminate_phase(); + extern local function void m_print_termination_state(); + extern local task wait_for_self_and_siblings_to_drop(); + extern function void kill(); + extern function void kill_successors(); // TBD add more useful debug //--------------------------------- @@ -232,29 +528,29 @@ class uvm_phase extends uvm_object; local static bit m_use_ovm_run_semantic; -//UVM function string convert2string(); -//UVM //return $sformatf("PHASE %s = %p",get_name(),this); -//UVM string s; -//UVM s = $sformatf("phase: %s parent=%s pred=%s succ=%s",get_name(), -//UVM (m_parent==null) ? "null" : get_schedule_name(), -//UVM m_aa2string(m_predecessors), -//UVM m_aa2string(m_successors)); -//UVM return s; -//UVM endfunction -//UVM -//UVM local function string m_aa2string(bit aa[uvm_phase]); // TBD tidy -//UVM string s; -//UVM int i; -//UVM s = "'{ "; -//UVM foreach (aa[ph]) begin -//UVM uvm_phase n = ph; -//UVM s = {s, (n == null) ? "null" : n.get_name(), -//UVM (i == aa.num()-1) ? "" : ", "}; -//UVM i++; -//UVM end -//UVM s = {s, " }"}; -//UVM return s; -//UVM endfunction + function string convert2string(); + //return $sformatf("PHASE %s = %p",get_name(),this); + string s; + s = $sformatf("phase: %s parent=%s pred=%s succ=%s",get_name(), + (m_parent==null) ? "null" : get_schedule_name(), + m_aa2string(m_predecessors), + m_aa2string(m_successors)); + return s; + endfunction + + local function string m_aa2string(bit aa[uvm_phase]); // TBD tidy + string s; + int i; + s = "'{ "; + foreach (aa[ph]) begin + uvm_phase n = ph; + s = {s, (n == null) ? "null" : n.get_name(), + (i == aa.num()-1) ? "" : ", "}; + i++; + end + s = {s, " }"}; + return s; + endfunction function bit is_domain(); return (m_phase_type == UVM_PHASE_DOMAIN); @@ -267,72 +563,66 @@ class uvm_phase extends uvm_object; succ.m_get_transitive_children(phases); end endfunction + + + // @uvm-ieee 1800.2-2017 auto 9.3.1.7.1 + function uvm_objection get_objection(); + uvm_phase imp; + uvm_task_phase tp; + imp = get_imp(); + // Only nodes with a non-null uvm_task_phase imp have objections + if ((get_phase_type() != UVM_PHASE_NODE) || (imp == null) || !$cast(tp, imp)) begin + return null; + end + if (phase_done == null) begin +`ifdef UVM_ENABLE_DEPRECATED_API + if (get_name() == "run") begin + phase_done = uvm_test_done_objection::get(); + end + else begin + `ifdef VERILATOR + phase_done = uvm_objection::type_id_create({get_name(), "_objection"}); + `else + phase_done = uvm_objection::type_id::create({get_name(), "_objection"}); + `endif + end +`else // !UVM_ENABLE_DEPRECATED_API + `ifdef VERILATOR + phase_done = uvm_objection::type_id_create({get_name(), "_objection"}); + `else + phase_done = uvm_objection::type_id::create({get_name(), "_objection"}); + `endif +`endif // UVM_ENABLE_DEPRECATED_API + end + + return phase_done; + endfunction // get_objection + + +endclass -//UVM // @uvm-ieee 1800.2-2017 auto 9.3.1.7.1 -//UVM function uvm_objection get_objection(); -//UVM uvm_phase imp; -//UVM uvm_task_phase tp; -//UVM imp = get_imp(); -//UVM // Only nodes with a non-null uvm_task_phase imp have objections -//UVM if ((get_phase_type() != UVM_PHASE_NODE) || (imp == null) || !$cast(tp, imp)) begin -//UVM return null; -//UVM end -//UVM if (phase_done == null) begin -//UVM `ifdef UVM_ENABLE_DEPRECATED_API -//UVM if (get_name() == "run") begin -//UVM phase_done = uvm_test_done_objection::get(); -//UVM end -//UVM else begin -//UVM `ifdef VERILATOR -//UVM phase_done = uvm_objection::type_id_create({get_name(), "_objection"}); -//UVM `else -//UVM phase_done = uvm_objection::type_id::create({get_name(), "_objection"}); -//UVM `endif -//UVM end -//UVM `else // !UVM_ENABLE_DEPRECATED_API -//UVM `ifdef VERILATOR -//UVM phase_done = uvm_objection::type_id_create({get_name(), "_objection"}); -//UVM `else -//UVM phase_done = uvm_objection::type_id::create({get_name(), "_objection"}); -//UVM `endif -//UVM `endif // UVM_ENABLE_DEPRECATED_API -//UVM end -//UVM -//UVM return phase_done; -//UVM endfunction // get_objection - - // UVM ! - extern function uvm_domain get_domain(); - extern function uvm_phase get_schedule(bit hier = 0); - extern function void jump(uvm_phase phase); - extern function void set_jump_phase(uvm_phase phase) ; - extern function void end_prematurely() ; - - local bit m_jump_bkwd; - local bit m_jump_fwd; - local uvm_phase m_jump_phase; - local bit m_premature_end; - - extern function void add(uvm_phase phase, - uvm_phase with_phase=null, - uvm_phase after_phase=null, - uvm_phase before_phase=null, - uvm_phase start_with_phase=null, - uvm_phase end_with_phase=null - ); -endclass +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_phase_state_change +// +//------------------------------------------------------------------------------ +// +// Phase state transition descriptor. +// Used to describe the phase transition that caused a +// callback to be invoked. +// -// UVM 1:1 +// @uvm-ieee 1800.2-2017 auto 9.3.2.1 class uvm_phase_state_change extends uvm_object; `uvm_object_utils(uvm_phase_state_change) // Implementation -- do not use directly - /* local */ uvm_phase m_phase;/* */ + /* local */ uvm_phase m_phase; /* local */ uvm_phase_state m_prev_state; /* local */ uvm_phase m_jump_to; - + function new(string name = "uvm_phase_state_change"); super.new(name); endfunction @@ -343,7 +633,7 @@ class uvm_phase_state_change extends uvm_object; virtual function uvm_phase_state get_state(); return m_phase.get_state(); endfunction - + // @uvm-ieee 1800.2-2017 auto 9.3.2.2.2 virtual function uvm_phase_state get_prev_state(); @@ -358,7 +648,20 @@ class uvm_phase_state_change extends uvm_object; endclass -// UVM 1:1 + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_phase_cb +// +//------------------------------------------------------------------------------ +// +// This class defines a callback method that is invoked by the phaser +// during the execution of a specific node in the phase graph or all phase nodes. +// User-defined callback extensions can be used to integrate data types that +// are not natively phase-aware with the UVM phasing. +// + +// @uvm-ieee 1800.2-2017 auto 9.3.3.1 class uvm_phase_cb extends uvm_callback; @@ -366,7 +669,7 @@ class uvm_phase_cb extends uvm_callback; function new(string name="unnamed-uvm_phase_cb"); super.new(name); endfunction : new - + // @uvm-ieee 1800.2-2017 auto 9.3.3.2.2 virtual function void phase_state_change(uvm_phase phase, @@ -375,10 +678,32 @@ class uvm_phase_cb extends uvm_callback; endclass //------------------------------------------------------------------------------ -// IMPLEMENTATION +// +// Class -- NODOCS -- uvm_phase_cb_pool +// +//------------------------------------------------------------------------------ +// +// Convenience type for the uvm_callbacks#(uvm_phase, uvm_phase_cb) class. +// +typedef uvm_callbacks#(uvm_phase, uvm_phase_cb) uvm_phase_cb_pool /* @uvm-ieee 1800.2-2017 auto D.4.1*/ ; + + //------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +typedef class uvm_cmdline_processor; + +`define UVM_PH_TRACE(ID,MSG,PH,VERB) \ + `uvm_info(ID, {$sformatf("Phase '%0s' (id=%0d) ", \ + PH.get_full_name(), PH.get_inst_id()),MSG}, VERB) + +//----------------------------- +// Implementation - Construction +//----------------------------- + +// new -// UVM ~ function uvm_phase::new(string name="uvm_phase", uvm_phase_type phase_type=UVM_PHASE_SCHEDULE, uvm_phase parent=null); @@ -390,28 +715,24 @@ function uvm_phase::new(string name="uvm_phase", if ((name == "common") && (phase_type == UVM_PHASE_DOMAIN)) m_state = UVM_PHASE_DORMANT; - + m_run_count = 0; m_parent = parent; - //UVM begin - //UVM uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); - //UVM string val; - //UVM if (clp.get_arg_value("+UVM_PHASE_TRACE", val)) - //UVM m_phase_trace = 1; - //UVM else - //UVM m_phase_trace = 0; - //UVM if (clp.get_arg_value("+UVM_USE_OVM_RUN_SEMANTIC", val)) - //UVM m_use_ovm_run_semantic = 1; - //UVM else - //UVM m_use_ovm_run_semantic = 0; - //UVM end - m_phase_trace = 0; - m_use_ovm_run_semantic = 0; - //UVM - - + begin + uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); + string val; + if (clp.get_arg_value("+UVM_PHASE_TRACE", val)) + m_phase_trace = 1; + else + m_phase_trace = 0; + if (clp.get_arg_value("+UVM_USE_OVM_RUN_SEMANTIC", val)) + m_use_ovm_run_semantic = 1; + else + m_use_ovm_run_semantic = 0; + end + if (parent == null && (phase_type == UVM_PHASE_SCHEDULE || phase_type == UVM_PHASE_DOMAIN )) begin //m_parent = this; @@ -422,304 +743,38 @@ function uvm_phase::new(string name="uvm_phase", endfunction -// UVM 1:1 -function uvm_phase_type uvm_phase::get_phase_type(); - return m_phase_type; -endfunction - -// UVM 1:1 -function void uvm_phase::set_max_ready_to_end_iterations(int max); - max_ready_to_end_iters = max; -endfunction - -// UVM 1:1 -function int uvm_phase::get_max_ready_to_end_iterations(); - return max_ready_to_end_iters; -endfunction -// UVM 1:1 -function void uvm_phase::set_default_max_ready_to_end_iterations(int max); - m_default_max_ready_to_end_iters = max; -endfunction +// add +// --- +// TBD error checks if param nodes are actually in this schedule or not -// UVM 1:1 -function int uvm_phase::get_default_max_ready_to_end_iterations(); - return m_default_max_ready_to_end_iters; -endfunction +function void uvm_phase::add(uvm_phase phase, + uvm_phase with_phase=null, + uvm_phase after_phase=null, + uvm_phase before_phase=null, + uvm_phase start_with_phase=null, + uvm_phase end_with_phase=null + ); + uvm_phase new_node, begin_node, end_node, tmp_node; + uvm_phase_state_change state_chg; -// UVM 1:1 -function uvm_phase_state uvm_phase::get_state(); - return m_state; -endfunction + if (phase == null) + `uvm_fatal("PH/NULL", "add: phase argument is null") -// UVM 1:1 -function int uvm_phase::get_run_count(); - return m_run_count; -endfunction + if (with_phase != null && with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = with_phase.get_name(); + with_phase = find(with_phase); + if (with_phase == null) + `uvm_fatal("PH_BAD_ADD", + {"cannot find with_phase '",nm,"' within node '",get_name(),"'"}) + end -// UVM 1:1 -function void uvm_phase::m_print_successors(); - uvm_phase found; - static string spaces = " "; - static int level; - if (m_phase_type == UVM_PHASE_DOMAIN) - level = 0; - `uvm_info("UVM/PHASE/SUCC",$sformatf("%s%s (%s) id=%0d",spaces.substr(0,level*2),get_name(), m_phase_type.name(),get_inst_id()),UVM_NONE) - level++; - foreach (m_successors[succ]) begin - succ.m_print_successors(); - end - level--; -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); - uvm_phase found; - //$display(" FIND PRED node '",phase.get_name(),"' (id=",$sformatf("%0d",phase.get_inst_id()),") - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); - if (phase == null) begin - return null ; - end - if (phase == m_imp || phase == this) - return this; - foreach (m_predecessors[pred]) begin - uvm_phase orig; - orig = (orig_phase==null) ? this : orig_phase; - if (!stay_in_scope || - (pred.get_schedule() == orig.get_schedule()) || - (pred.get_domain() == orig.get_domain())) begin - found = pred.m_find_predecessor(phase,stay_in_scope,orig); - if (found != null) - return found; - end - end - return null; -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); - uvm_phase found; - //$display(" FIND PRED node '",name,"' - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); - if (get_name() == name) - return this; - foreach (m_predecessors[pred]) begin - uvm_phase orig; - orig = (orig_phase==null) ? this : orig_phase; - if (!stay_in_scope || - (pred.get_schedule() == orig.get_schedule()) || - (pred.get_domain() == orig.get_domain())) begin - found = pred.m_find_predecessor_by_name(name,stay_in_scope,orig); - if (found != null) - return found; - end - end - return null; -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); - uvm_phase found; - //$display(" FIND SUCC node '",phase.get_name(),"' (id=",$sformatf("%0d",phase.get_inst_id()),") - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); - if (phase == null) begin - return null ; - end - if (phase == m_imp || phase == this) begin - return this; - end - foreach (m_successors[succ]) begin - uvm_phase orig; - orig = (orig_phase==null) ? this : orig_phase; - if (!stay_in_scope || - (succ.get_schedule() == orig.get_schedule()) || - (succ.get_domain() == orig.get_domain())) begin - found = succ.m_find_successor(phase,stay_in_scope,orig); - if (found != null) begin - return found; - end - end - end - return null; -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); - uvm_phase found; - //$display(" FIND SUCC node '",name,"' - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); - if (get_name() == name) - return this; - foreach (m_successors[succ]) begin - uvm_phase orig; - orig = (orig_phase==null) ? this : orig_phase; - if (!stay_in_scope || - (succ.get_schedule() == orig.get_schedule()) || - (succ.get_domain() == orig.get_domain())) begin - found = succ.m_find_successor_by_name(name,stay_in_scope,orig); - if (found != null) - return found; - end - end - return null; -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::find(uvm_phase phase, bit stay_in_scope=1); - // TBD full search - //$display({"\nFIND node '",phase.get_name(),"' within ",get_name()," (scope ",m_phase_type.name(),")", (stay_in_scope) ? " staying within scope" : ""}); - if (phase == m_imp || phase == this) - return phase; - find = m_find_predecessor(phase,stay_in_scope,this); - if (find == null) - find = m_find_successor(phase,stay_in_scope,this); -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::find_by_name(string name, bit stay_in_scope=1); - // TBD full search - //$display({"\nFIND node named '",name,"' within ",get_name()," (scope ",m_phase_type.name(),")", (stay_in_scope) ? " staying within scope" : ""}); - if (get_name() == name) - return this; - find_by_name = m_find_predecessor_by_name(name,stay_in_scope,this); - if (find_by_name == null) - find_by_name = m_find_successor_by_name(name,stay_in_scope,this); -endfunction - -// UVM 1:1 -function bit uvm_phase::is(uvm_phase phase); - return (m_imp == phase || this == phase); -endfunction - -// UVM 1:1 -function bit uvm_phase::is_before(uvm_phase phase); - //$display("this=%s is before phase=%s?",get_name(),phase.get_name()); - // TODO: add support for 'stay_in_scope=1' functionality - return (!is(phase) && m_find_successor(phase,0,this) != null); -endfunction - -// UVM 1:1 -function bit uvm_phase::is_after(uvm_phase phase); - //$display("this=%s is after phase=%s?",get_name(),phase.get_name()); - // TODO: add support for 'stay_in_scope=1' functionality - return (!is(phase) && m_find_predecessor(phase,0,this) != null); -endfunction - -// UVM 1:1 -function uvm_domain uvm_phase::get_domain(); - uvm_phase phase; - phase = this; - while (phase != null && phase.m_phase_type != UVM_PHASE_DOMAIN) - phase = phase.m_parent; - if (phase == null) // no parent domain - return null; - if(!$cast(get_domain,phase)) - `uvm_fatal("PH/INTERNAL", "get_domain: m_phase_type is DOMAIN but $cast to uvm_domain fails") -endfunction - -// UVM 1:1 -function uvm_phase uvm_phase::get_schedule(bit hier=0); - uvm_phase sched; - sched = this; - if (hier) - while (sched.m_parent != null && (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) - sched = sched.m_parent; - if (sched.m_phase_type == UVM_PHASE_SCHEDULE) - return sched; - if (sched.m_phase_type == UVM_PHASE_NODE) - if (m_parent != null && m_parent.m_phase_type != UVM_PHASE_DOMAIN) - return m_parent; - return null; -endfunction - -// UVM 1:1 -function void uvm_phase::end_prematurely() ; - m_premature_end = 1 ; -endfunction - -// UVM 1:1 -function void uvm_phase::jump(uvm_phase phase); - set_jump_phase(phase) ; - end_prematurely() ; -endfunction - -// UVM 1:1 -function void uvm_phase::set_jump_phase(uvm_phase phase) ; - uvm_phase d; - - if ((m_state < UVM_PHASE_STARTED) || - (m_state > UVM_PHASE_ENDED) ) - begin - `uvm_error("JMPPHIDL", { "Attempting to jump from phase \"", - get_name(), "\" which is not currently active (current state is ", - m_state.name(), "). The jump will not happen until the phase becomes ", - "active."}) - end - - - - // A jump can be either forward or backwards in the phase graph. - // If the specified phase (name) is found in the set of predecessors - // then we are jumping backwards. If, on the other hand, the phase is in the set - // of successors then we are jumping forwards. If neither, then we - // have an error. - // - // If the phase is non-existant and thus we don't know where to jump - // we have a situation where the only thing to do is to uvm_report_fatal - // and terminate_phase. By calling this function the intent was to - // jump to some other phase. So, continuing in the current phase doesn't - // make any sense. And we don't have a valid phase to jump to. So we're done. - - d = m_find_predecessor(phase,0); - if (d == null) begin - d = m_find_successor(phase,0); - if (d == null) begin - string msg; - $sformat(msg,{"phase %s is neither a predecessor or successor of ", - "phase %s or is non-existant, so we cannot jump to it. ", - "Phase control flow is now undefined so the simulation ", - "must terminate"}, phase.get_name(), get_name()); - `uvm_fatal("PH_BADJUMP", msg) - end - else begin - m_jump_fwd = 1; - `uvm_info("PH_JUMPF",$sformatf("jumping forward to phase %s", phase.get_name()), - UVM_DEBUG) - end - end - else begin - m_jump_bkwd = 1; - `uvm_info("PH_JUMPB",$sformatf("jumping backward to phase %s", phase.get_name()), - UVM_DEBUG) - end - - m_jump_phase = d; -endfunction - -// UVM 1:1 -function void uvm_phase::add(uvm_phase phase, - uvm_phase with_phase=null, - uvm_phase after_phase=null, - uvm_phase before_phase=null, - uvm_phase start_with_phase=null, - uvm_phase end_with_phase=null - ); - uvm_phase new_node, begin_node, end_node, tmp_node; - uvm_phase_state_change state_chg; - - if (phase == null) - `uvm_fatal("PH/NULL", "add: phase argument is null") - - if (with_phase != null && with_phase.get_phase_type() == UVM_PHASE_IMP) begin - string nm = with_phase.get_name(); - with_phase = find(with_phase); - if (with_phase == null) - `uvm_fatal("PH_BAD_ADD", - {"cannot find with_phase '",nm,"' within node '",get_name(),"'"}) - end - - if (before_phase != null && before_phase.get_phase_type() == UVM_PHASE_IMP) begin - string nm = before_phase.get_name(); - before_phase = find(before_phase); - if (before_phase == null) - `uvm_fatal("PH_BAD_ADD", - {"cannot find before_phase '",nm,"' within node '",get_name(),"'"}) + if (before_phase != null && before_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = before_phase.get_name(); + before_phase = find(before_phase); + if (before_phase == null) + `uvm_fatal("PH_BAD_ADD", + {"cannot find before_phase '",nm,"' within node '",get_name(),"'"}) end if (after_phase != null && after_phase.get_phase_type() == UVM_PHASE_IMP) begin @@ -754,11 +809,11 @@ function void uvm_phase::add(uvm_phase phase, `uvm_fatal("PH_BAD_ADD", "only one of with_phase/before_phase/end_with_phase may be specified as they all specify successor") - if (before_phase == this || - after_phase == m_end_node || + if (before_phase == this || + after_phase == m_end_node || with_phase == m_end_node || start_with_phase == m_end_node || - end_with_phase == m_end_node) + end_with_phase == m_end_node) `uvm_fatal("PH_BAD_ADD", "cannot add before begin node, after end node, or with end nodes") @@ -785,7 +840,7 @@ function void uvm_phase::add(uvm_phase phase, // If we are inserting a new "leaf node" if (phase.get_phase_type() == UVM_PHASE_IMP) begin -//UVM uvm_task_phase tp; + uvm_task_phase tp; new_node = new(phase.get_name(),UVM_PHASE_NODE,this); new_node.m_imp = phase; begin_node = new_node; @@ -808,7 +863,7 @@ function void uvm_phase::add(uvm_phase phase, */ // If no before/after/with specified, insert at end of this schedule - if (with_phase==null && after_phase==null && before_phase==null && + if (with_phase==null && after_phase==null && before_phase==null && start_with_phase==null && end_with_phase==null) begin before_phase = m_end_node; end @@ -819,11 +874,11 @@ function void uvm_phase::add(uvm_phase phase, `uvm_info("PH/TRC/ADD_PH", {get_name()," (",m_phase_type.name(),") ADD_PHASE: phase=",phase.get_full_name()," (", typ.name(),", inst_id=",$sformatf("%0d",phase.get_inst_id()),")", - " with_phase=", (with_phase == null) ? "null" : with_phase.get_name(), - " start_with_phase=", (start_with_phase == null) ? "null" : start_with_phase.get_name(), - " end_with_phase=", (end_with_phase == null) ? "null" : end_with_phase.get_name(), + " with_phase=", (with_phase == null) ? "null" : with_phase.get_name(), + " start_with_phase=", (start_with_phase == null) ? "null" : start_with_phase.get_name(), + " end_with_phase=", (end_with_phase == null) ? "null" : end_with_phase.get_name(), " after_phase=", (after_phase == null) ? "null" : after_phase.get_name(), - " before_phase=", (before_phase == null) ? "null" : before_phase.get_name(), + " before_phase=", (before_phase == null) ? "null" : before_phase.get_name(), " new_node=", (new_node == null) ? "null" : {new_node.get_name(), " inst_id=", $sformatf("%0d",new_node.get_inst_id())}, @@ -832,7 +887,7 @@ function void uvm_phase::add(uvm_phase phase, end - // + // // INSERT IN PARALLEL WITH 'WITH' PHASE if (with_phase != null) begin // all pre-existing predecessors to with_phase are predecessors to the new phase @@ -842,7 +897,7 @@ function void uvm_phase::add(uvm_phase phase, end_node.m_successors = with_phase.m_successors; foreach (with_phase.m_successors[succ]) succ.m_predecessors[end_node] = 1; end - + if (start_with_phase != null) begin // all pre-existing predecessors to start_with_phase are predecessors to the new phase begin_node.m_predecessors = start_with_phase.m_predecessors; @@ -857,7 +912,7 @@ function void uvm_phase::add(uvm_phase phase, end end end - + if (end_with_phase != null) begin // all pre-existing successors to end_with_phase are successors to the new phase end_node.m_successors = end_with_phase.m_successors; @@ -875,7 +930,7 @@ function void uvm_phase::add(uvm_phase phase, // INSERT BEFORE PHASE if (before_phase != null) begin - // unless predecessors to this phase are otherwise specified, + // unless predecessors to this phase are otherwise specified, // pre-existing predecessors to before_phase move to be predecessors to the new phase if (after_phase == null && start_with_phase == null) begin foreach (before_phase.m_predecessors[pred]) begin @@ -901,7 +956,7 @@ function void uvm_phase::add(uvm_phase phase, // INSERT AFTER PHASE if (after_phase != null) begin - // unless successors to this phase are otherwise specified, + // unless successors to this phase are otherwise specified, // pre-existing successors to after_phase are now successors to this phase if (before_phase == null && end_with_phase == null) begin foreach (after_phase.m_successors[succ]) begin @@ -917,12 +972,12 @@ function void uvm_phase::add(uvm_phase phase, after_phase.m_successors.delete(before_phase); end - // after_phase is the sole predecessor of this phase + // after_phase is the sole predecessor of this phase after_phase.m_successors[begin_node] = 1; begin_node.m_predecessors.delete(); begin_node.m_predecessors[after_phase] = 1; end - + // Transition nodes to DORMANT state @@ -931,14 +986,1334 @@ function void uvm_phase::add(uvm_phase phase, else tmp_node = new_node; -//UVM `ifdef VERILATOR -//UVM state_chg = uvm_phase_state_change::type_id_create(tmp_node.get_name()); -//UVM `else +`ifdef VERILATOR + state_chg = uvm_phase_state_change::type_id_create(tmp_node.get_name()); +`else state_chg = uvm_phase_state_change::type_id::create(tmp_node.get_name()); -//UVM `endif +`endif state_chg.m_phase = tmp_node; state_chg.m_jump_to = null; state_chg.m_prev_state = tmp_node.m_state; tmp_node.m_state = UVM_PHASE_DORMANT; - `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(tmp_node, state_chg)) + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(tmp_node, state_chg)) +endfunction + + +// get_parent +// ---------- + +function uvm_phase uvm_phase::get_parent(); + return m_parent; +endfunction + + +// get_imp +// ------- + +function uvm_phase uvm_phase::get_imp(); + return m_imp; +endfunction + + +// get_schedule +// ------------ + +function uvm_phase uvm_phase::get_schedule(bit hier=0); + uvm_phase sched; + sched = this; + if (hier) + while (sched.m_parent != null && (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) + sched = sched.m_parent; + if (sched.m_phase_type == UVM_PHASE_SCHEDULE) + return sched; + if (sched.m_phase_type == UVM_PHASE_NODE) + if (m_parent != null && m_parent.m_phase_type != UVM_PHASE_DOMAIN) + return m_parent; + return null; endfunction + + +// get_domain +// ---------- + +function uvm_domain uvm_phase::get_domain(); + uvm_phase phase; + phase = this; + while (phase != null && phase.m_phase_type != UVM_PHASE_DOMAIN) + phase = phase.m_parent; + if (phase == null) // no parent domain + return null; + if(!$cast(get_domain,phase)) + `uvm_fatal("PH/INTERNAL", "get_domain: m_phase_type is DOMAIN but $cast to uvm_domain fails") +endfunction + + +// get_domain_name +// --------------- + +function string uvm_phase::get_domain_name(); + uvm_domain domain; + domain = get_domain(); + if (domain == null) + return "unknown"; + return domain.get_name(); +endfunction + + +// get_schedule_name +// ----------------- + +function string uvm_phase::get_schedule_name(bit hier=0); + uvm_phase sched; + string s; + sched = get_schedule(hier); + if (sched == null) + return ""; + s = sched.get_name(); + while (sched.m_parent != null && sched.m_parent != sched && + (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) begin + sched = sched.m_parent; + s = {sched.get_name(),(s.len()>0?".":""),s}; + end + return s; +endfunction + + +// get_full_name +// ------------- + +function string uvm_phase::get_full_name(); + string dom, sch; + if (m_phase_type == UVM_PHASE_IMP) + return get_name(); + get_full_name = get_domain_name(); + sch = get_schedule_name(); + if (sch != "") + get_full_name = {get_full_name, ".", sch}; + if (m_phase_type != UVM_PHASE_DOMAIN && m_phase_type != UVM_PHASE_SCHEDULE) + get_full_name = {get_full_name, ".", get_name()}; +endfunction + + +// get_phase_type +// -------------- + +function uvm_phase_type uvm_phase::get_phase_type(); + return m_phase_type; +endfunction + +// set_max_ready_to_end_iterations +// ------------------------------- + +function void uvm_phase::set_max_ready_to_end_iterations(int max); + max_ready_to_end_iters = max; +endfunction + +// get_max_ready_to_end_iterations +// ------------------------------- + +function int uvm_phase::get_max_ready_to_end_iterations(); + return max_ready_to_end_iters; +endfunction + +// set_default_max_ready_to_end_iterations +// --------------------------------------- + +function void uvm_phase::set_default_max_ready_to_end_iterations(int max); + m_default_max_ready_to_end_iters = max; +endfunction + +// get_default_max_ready_to_end_iterations +// --------------------------------------- + +function int uvm_phase::get_default_max_ready_to_end_iterations(); + return m_default_max_ready_to_end_iters; +endfunction + + +//----------------------- +// Implementation - State +//----------------------- + +// get_state +// --------- + +function uvm_phase_state uvm_phase::get_state(); + return m_state; +endfunction + +// get_run_count +// ------------- + +function int uvm_phase::get_run_count(); + return m_run_count; +endfunction + + +// m_print_successors +// ------------------ + +function void uvm_phase::m_print_successors(); + uvm_phase found; + static string spaces = " "; + static int level; + if (m_phase_type == UVM_PHASE_DOMAIN) + level = 0; + `uvm_info("UVM/PHASE/SUCC",$sformatf("%s%s (%s) id=%0d",spaces.substr(0,level*2),get_name(), m_phase_type.name(),get_inst_id()),UVM_NONE) + level++; + foreach (m_successors[succ]) begin + succ.m_print_successors(); + end + level--; +endfunction + + +// m_find_predecessor +// ------------------ + +function uvm_phase uvm_phase::m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + //$display(" FIND PRED node '",phase.get_name(),"' (id=",$sformatf("%0d",phase.get_inst_id()),") - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); + if (phase == null) begin + return null ; + end + if (phase == m_imp || phase == this) + return this; + foreach (m_predecessors[pred]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (pred.get_schedule() == orig.get_schedule()) || + (pred.get_domain() == orig.get_domain())) begin + found = pred.m_find_predecessor(phase,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction + + +// m_find_predecessor_by_name +// -------------------------- + +function uvm_phase uvm_phase::m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + //$display(" FIND PRED node '",name,"' - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); + if (get_name() == name) + return this; + foreach (m_predecessors[pred]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (pred.get_schedule() == orig.get_schedule()) || + (pred.get_domain() == orig.get_domain())) begin + found = pred.m_find_predecessor_by_name(name,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction + + +// m_find_successor +// ---------------- + +function uvm_phase uvm_phase::m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + //$display(" FIND SUCC node '",phase.get_name(),"' (id=",$sformatf("%0d",phase.get_inst_id()),") - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); + if (phase == null) begin + return null ; + end + if (phase == m_imp || phase == this) begin + return this; + end + foreach (m_successors[succ]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (succ.get_schedule() == orig.get_schedule()) || + (succ.get_domain() == orig.get_domain())) begin + found = succ.m_find_successor(phase,stay_in_scope,orig); + if (found != null) begin + return found; + end + end + end + return null; +endfunction + + +// m_find_successor_by_name +// ------------------------ + +function uvm_phase uvm_phase::m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + //$display(" FIND SUCC node '",name,"' - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")"); + if (get_name() == name) + return this; + foreach (m_successors[succ]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (succ.get_schedule() == orig.get_schedule()) || + (succ.get_domain() == orig.get_domain())) begin + found = succ.m_find_successor_by_name(name,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction + + +// find +// ---- + +function uvm_phase uvm_phase::find(uvm_phase phase, bit stay_in_scope=1); + // TBD full search + //$display({"\nFIND node '",phase.get_name(),"' within ",get_name()," (scope ",m_phase_type.name(),")", (stay_in_scope) ? " staying within scope" : ""}); + if (phase == m_imp || phase == this) + return phase; + find = m_find_predecessor(phase,stay_in_scope,this); + if (find == null) + find = m_find_successor(phase,stay_in_scope,this); +endfunction + + +// find_by_name +// ------------ + +function uvm_phase uvm_phase::find_by_name(string name, bit stay_in_scope=1); + // TBD full search + //$display({"\nFIND node named '",name,"' within ",get_name()," (scope ",m_phase_type.name(),")", (stay_in_scope) ? " staying within scope" : ""}); + if (get_name() == name) + return this; + find_by_name = m_find_predecessor_by_name(name,stay_in_scope,this); + if (find_by_name == null) + find_by_name = m_find_successor_by_name(name,stay_in_scope,this); +endfunction + + +// is +// -- + +function bit uvm_phase::is(uvm_phase phase); + return (m_imp == phase || this == phase); +endfunction + + +// is_before +// --------- + +function bit uvm_phase::is_before(uvm_phase phase); + //$display("this=%s is before phase=%s?",get_name(),phase.get_name()); + // TODO: add support for 'stay_in_scope=1' functionality + return (!is(phase) && m_find_successor(phase,0,this) != null); +endfunction + + +// is_after +// -------- + +function bit uvm_phase::is_after(uvm_phase phase); + //$display("this=%s is after phase=%s?",get_name(),phase.get_name()); + // TODO: add support for 'stay_in_scope=1' functionality + return (!is(phase) && m_find_predecessor(phase,0,this) != null); +endfunction + + +// execute_phase +// ------------- + +task uvm_phase::execute_phase(); + + uvm_task_phase task_phase; + uvm_root top; + uvm_phase_state_change state_chg; + uvm_coreservice_t cs; + + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + // If we got here by jumping forward, we must wait for + // all its predecessor nodes to be marked DONE. + // (the next conditional speeds this up) + // Also, this helps us fast-forward through terminal (end) nodes + foreach (m_predecessors[pred]) + wait (pred.m_state == UVM_PHASE_DONE); + + + // If DONE (by, say, a forward jump), return immed + if (m_state == UVM_PHASE_DONE) + return; + +`ifdef VERILATOR + state_chg = uvm_phase_state_change::type_id_create(get_name()); +`else + state_chg = uvm_phase_state_change::type_id::create(get_name()); +`endif + state_chg.m_phase = this; + state_chg.m_jump_to = null; + + //--------- + // SYNCING: + //--------- + // Wait for phases with which we have a sync() + // relationship to be ready. Sync can be 2-way - + // this additional state avoids deadlock. + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_SYNCING; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + #0; + + if (m_sync.size()) begin + + foreach (m_sync[i]) begin + wait (m_sync[i].m_state >= UVM_PHASE_SYNCING); + end + end + + m_run_count++; + + + if (m_phase_trace) begin + `UVM_PH_TRACE("PH/TRC/STRT","Starting phase",this,UVM_LOW) + end + + + // If we're a schedule or domain, then "fake" execution + if (m_phase_type != UVM_PHASE_NODE) begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_STARTED; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + + #0; + + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + + #0; + end + + + else begin // PHASE NODE + + //--------- + // STARTED: + //--------- + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_STARTED; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + + m_imp.traverse(top,this,UVM_PHASE_STARTED); + m_ready_to_end_count = 0 ; // reset the ready_to_end count when phase starts + #0; // LET ANY WAITERS WAKE UP + + + //if (m_imp.get_phase_type() != UVM_PHASE_TASK) begin + if (!$cast(task_phase,m_imp)) begin + + //----------- + // EXECUTING: (function phases) + //----------- + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + + #0; // LET ANY WAITERS WAKE UP + m_imp.traverse(top,this,UVM_PHASE_EXECUTING); + + end + else begin + m_executing_phases[this] = 1; + + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + + fork : master_phase_process + begin + + m_phase_proc = process::self(); + + //----------- + // EXECUTING: (task phases) + //----------- + task_phase.traverse(top,this,UVM_PHASE_EXECUTING); + + wait(0); // stay alive for later kill + + end + join_none + + uvm_wait_for_nba_region(); //Give sequences, etc. a chance to object + + // Now wait for one of three criterion for end-of-phase. + fork + begin // guard + + fork + // JUMP + begin + wait (m_premature_end); + `UVM_PH_TRACE("PH/TRC/EXE/JUMP","PHASE EXIT ON JUMP REQUEST",this,UVM_DEBUG) + end + + // WAIT_FOR_ALL_DROPPED + begin + bit do_ready_to_end ; // bit used for ready_to_end iterations + uvm_objection phase_done; + phase_done = get_objection(); + // OVM semantic: don't end until objection raised or stop request + if (phase_done.get_objection_total(top) || + m_use_ovm_run_semantic && m_imp.get_name() == "run") begin + if (!phase_done.m_top_all_dropped) + phase_done.wait_for(UVM_ALL_DROPPED, top); + `UVM_PH_TRACE("PH/TRC/EXE/ALLDROP","PHASE EXIT ALL_DROPPED",this,UVM_DEBUG) + end + else begin + if (m_phase_trace) `UVM_PH_TRACE("PH/TRC/SKIP","No objections raised, skipping phase",this,UVM_LOW) + end + + wait_for_self_and_siblings_to_drop() ; + do_ready_to_end = 1; + + //-------------- + // READY_TO_END: + //-------------- + + while (do_ready_to_end) begin + uvm_wait_for_nba_region(); // Let all siblings see no objections before traverse might raise another + `UVM_PH_TRACE("PH_READY_TO_END","PHASE READY TO END",this,UVM_DEBUG) + m_ready_to_end_count++; + if (m_phase_trace) + `UVM_PH_TRACE("PH_READY_TO_END_CB","CALLING READY_TO_END CB",this,UVM_HIGH) + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_READY_TO_END; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + if (m_imp != null) + m_imp.traverse(top,this,UVM_PHASE_READY_TO_END); + + uvm_wait_for_nba_region(); // Give traverse targets a chance to object + + wait_for_self_and_siblings_to_drop(); + do_ready_to_end = (m_state == UVM_PHASE_EXECUTING) && (m_ready_to_end_count < get_max_ready_to_end_iterations()) ; //when we don't wait in task above, we drop out of while loop + end + end + + // TIMEOUT + begin + if (this.get_name() == "run") begin + if (top.phase_timeout == 0) + wait(top.phase_timeout != 0); + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/TO_WAIT", $sformatf("STARTING PHASE TIMEOUT WATCHDOG (timeout == %t)", top.phase_timeout), this, UVM_HIGH) + `uvm_delay(top.phase_timeout) + if ($time == `UVM_DEFAULT_TIMEOUT) begin + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED", this, UVM_LOW) + foreach (m_executing_phases[p]) begin + uvm_objection p_phase_done; + p_phase_done = p.get_objection(); + if ((p_phase_done != null) && (p_phase_done.get_objection_total() > 0)) begin + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN", + $sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p_phase_done.convert2string()), + this, + UVM_LOW) + end + end + + `uvm_fatal("PH_TIMEOUT", + $sformatf("Default timeout of %0t hit, indicating a probable testbench issue", + `UVM_DEFAULT_TIMEOUT)) + end + else begin + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED", this, UVM_LOW) + foreach (m_executing_phases[p]) begin + uvm_objection p_phase_done; + p_phase_done = p.get_objection(); + if ((p_phase_done != null) && (p_phase_done.get_objection_total() > 0)) begin + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN", + $sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p_phase_done.convert2string()), + this, + UVM_LOW) + end + end + + `uvm_fatal("PH_TIMEOUT", + $sformatf("Explicit timeout of %0t hit, indicating a probable testbench issue", + top.phase_timeout)) + end + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/EXE/3","PHASE EXIT TIMEOUT",this,UVM_DEBUG) + end // if (this.get_name() == "run") + else begin + wait (0); // never unblock for non-run phase + end + end // if (m_phase_trace) + + + join_any + disable fork; + + end + + join // guard + + end + + end + + m_executing_phases.delete(this); + + //--------- + // JUMPING: + //--------- + + // If jump_to() was called then we need to kill all the successor + // phases which may still be running and then initiate the new + // phase. The return is necessary so we don't start new successor + // phases. If we are doing a forward jump then we want to set the + // state of this phase's successors to UVM_PHASE_DONE. This + // will let us pretend that all the phases between here and there + // were executed and completed. Thus any dependencies will be + // satisfied preventing deadlocks. + // GSA TBD insert new jump support + + if (m_phase_type == UVM_PHASE_NODE) begin + + if(m_premature_end) begin + if(m_jump_phase != null) begin + state_chg.m_jump_to = m_jump_phase; + + `uvm_info("PH_JUMP", + $sformatf("phase %s (schedule %s, domain %s) is jumping to phase %s", + get_name(), get_schedule_name(), get_domain_name(), m_jump_phase.get_name()), + UVM_MEDIUM) + end + else begin + `uvm_info("PH_JUMP", + $sformatf("phase %s (schedule %s, domain %s) is ending prematurely", + get_name(), get_schedule_name(), get_domain_name()), + UVM_MEDIUM) + end + + + #0; // LET ANY WAITERS ON READY_TO_END TO WAKE UP + if (m_phase_trace) + `UVM_PH_TRACE("PH_END","ENDING PHASE PREMATURELY",this,UVM_HIGH) + end + else begin + // WAIT FOR PREDECESSORS: // WAIT FOR PREDECESSORS: + // function phases only + if (task_phase == null) + m_wait_for_pred(); + end + + //------- + // ENDED: + //------- + // execute 'phase_ended' callbacks + if (m_phase_trace) + `UVM_PH_TRACE("PH_END","ENDING PHASE",this,UVM_HIGH) + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_ENDED; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + if (m_imp != null) + m_imp.traverse(top,this,UVM_PHASE_ENDED); + #0; // LET ANY WAITERS WAKE UP + + + //--------- + // CLEANUP: + //--------- + // kill this phase's threads + state_chg.m_prev_state = m_state; + if(m_premature_end) m_state = UVM_PHASE_JUMPING; + else m_state = UVM_PHASE_CLEANUP ; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + if (m_phase_proc != null) begin + m_phase_proc.kill(); + m_phase_proc = null; + end + #0; // LET ANY WAITERS WAKE UP + begin + uvm_objection objection = get_objection(); + if (objection != null) + objection.clear(); + end + end + + //------ + // DONE: + //------ + m_premature_end = 0 ; + if(m_jump_fwd || m_jump_bkwd) begin + if(m_jump_fwd) begin + clear_successors(UVM_PHASE_DONE,m_jump_phase); + end + m_jump_phase.clear_successors(); + end + else begin + + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/DONE","Completed phase",this,UVM_LOW) + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_DONE; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg)) + m_phase_proc = null; + #0; // LET ANY WAITERS WAKE UP + end + #0; // LET ANY WAITERS WAKE UP + begin + uvm_objection objection; + objection = get_objection(); + if (objection != null) + objection.clear(); + end + +//----------- +// SCHEDULED: +//----------- + if(m_jump_fwd || m_jump_bkwd) begin + void'(m_phase_hopper.try_put(m_jump_phase)); + m_jump_phase = null; + m_jump_fwd = 0; + m_jump_bkwd = 0; + end + // If more successors, schedule them to run now + else if (m_successors.size() == 0) begin + top.m_phase_all_done=1; + end + else begin + // execute all the successors + foreach (m_successors[succ]) begin + if(succ.m_state < UVM_PHASE_SCHEDULED) begin + state_chg.m_prev_state = succ.m_state; + state_chg.m_phase = succ; + succ.m_state = UVM_PHASE_SCHEDULED; + `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(succ, state_chg)) + #0; // LET ANY WAITERS WAKE UP + void'(m_phase_hopper.try_put(succ)); + if (m_phase_trace) + `UVM_PH_TRACE("PH/TRC/SCHEDULED",{"Scheduled from phase ",get_full_name()},succ,UVM_LOW) + end + end + end + +endtask + +function void uvm_phase::get_adjacent_predecessor_nodes(ref uvm_phase pred[]); + bit done; + bit predecessors[uvm_phase]; + int idx; + + // Get all predecessors (including TERMINALS, SCHEDULES, etc.) + foreach (m_predecessors[p]) + predecessors[p] = 1; + + // Replace any terminal / schedule nodes with their predecessors, + // recursively. + do begin + done = 1; + foreach (predecessors[p]) begin + if (p.get_phase_type() != UVM_PHASE_NODE) begin + predecessors.delete(p); + foreach (p.m_predecessors[next_p]) + predecessors[next_p] = 1; + done = 0; + end + end + end while (!done); + + pred = new [predecessors.size()]; + foreach (predecessors[p]) begin + pred[idx++] = p; + end +endfunction : get_adjacent_predecessor_nodes + +function void uvm_phase::get_adjacent_successor_nodes(ref uvm_phase succ[]); + bit done; + bit successors[uvm_phase]; + int idx; + + // Get all successors (including TERMINALS, SCHEDULES, etc.) + foreach (m_successors[s]) + successors[s] = 1; + + // Replace any terminal / schedule nodes with their successors, + // recursively. + do begin + done = 1; + foreach (successors[s]) begin + if (s.get_phase_type() != UVM_PHASE_NODE) begin + successors.delete(s); + foreach (s.m_successors[next_s]) + successors[next_s] = 1; + done = 0; + end + end + end while (!done); + + succ = new [successors.size()]; + foreach (successors[s]) begin + succ[idx++] = s; + end +endfunction : get_adjacent_successor_nodes + +// Internal implementation, more efficient than calling get_predessor_nodes on all +// of the successors returned by get_adjacent_successor_nodes +function void uvm_phase::get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); + bit done; + uvm_phase successors[]; + + get_adjacent_successor_nodes(successors); + + // get all predecessors to these successors + foreach (successors[s]) + foreach (successors[s].m_predecessors[pred]) + pred_of_succ[pred] = 1; + + // replace any terminal nodes with their predecessors, recursively. + // we are only interested in "real" phase nodes + do begin + done=1; + foreach (pred_of_succ[pred]) begin + if (pred.get_phase_type() != UVM_PHASE_NODE) begin + pred_of_succ.delete(pred); + foreach (pred.m_predecessors[next_pred]) + pred_of_succ[next_pred] = 1; + done =0; + end + end + end while (!done); + + + // remove ourselves from the list + pred_of_succ.delete(this); +endfunction + + +// m_wait_for_pred +// --------------- + +task uvm_phase::m_wait_for_pred(); + + bit pred_of_succ[uvm_phase]; + get_predecessors_for_successors(pred_of_succ); + + // wait for predecessors to successors (real phase nodes, not terminals) + // mostly debug msgs + foreach (pred_of_succ[sibling]) begin + + if (m_phase_trace) begin + string s; + s = $sformatf("Waiting for phase '%s' (%0d) to be READY_TO_END. Current state is %s", + sibling.get_name(),sibling.get_inst_id(),sibling.m_state.name()); + `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC",s,this,UVM_HIGH) + end + + sibling.wait_for_state(UVM_PHASE_READY_TO_END, UVM_GTE); + + if (m_phase_trace) begin + string s; + s = $sformatf("Phase '%s' (%0d) is now READY_TO_END. Releasing phase", + sibling.get_name(),sibling.get_inst_id()); + `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC",s,this,UVM_HIGH) + end + + end + + if (m_phase_trace) begin + if (pred_of_succ.num()) begin + string s = "( "; + foreach (pred_of_succ[pred]) + s = {s, pred.get_full_name()," "}; + s = {s, ")"}; + `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC", + {"*** All pred to succ ",s," in READY_TO_END state, so ending phase ***"},this,UVM_HIGH) + end + else begin + `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC", + "*** No pred to succ other than myself, so ending phase ***",this,UVM_HIGH) + end + end + + #0; // LET ANY WAITERS WAKE UP + +endtask + + +//--------------------------------- +// Implementation - Synchronization +//--------------------------------- + +function void uvm_phase::m_report_null_objection(uvm_object obj, + string description, + int count, + string action); + string m_action; + string m_addon; + string m_obj_name = (obj == null) ? "uvm_top" : obj.get_full_name(); + + if ((action == "raise") || (action == "drop")) begin + if (count != 1) + m_action = $sformatf("%s %0d objections", action, count); + else + m_action = $sformatf("%s an objection", action); + end + else if (action == "get_objection_count") begin + m_action = "call get_objection_count"; + end + + if (this.get_phase_type() == UVM_PHASE_IMP) begin + m_addon = " (This is a UVM_PHASE_IMP, you have to query the schedule to find the UVM_PHASE_NODE)"; + end + + `uvm_error("UVM/PH/NULL_OBJECTION", + $sformatf("'%s' attempted to %s on '%s', however '%s' is not a task-based phase node! %s", + m_obj_name, + m_action, + get_name(), + get_name(), + m_addon)) +endfunction : m_report_null_objection + + +// raise_objection +// --------------- + +function void uvm_phase::raise_objection (uvm_object obj, + string description="", + int count=1); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.raise_objection(obj,description,count); + else + m_report_null_objection(obj, description, count, "raise"); +endfunction + + +// drop_objection +// -------------- + +function void uvm_phase::drop_objection (uvm_object obj, + string description="", + int count=1); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.drop_objection(obj,description,count); + else + m_report_null_objection(obj, description, count, "drop"); +endfunction + +// get_objection_count +// ------------------- + +function int uvm_phase::get_objection_count (uvm_object obj=null); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + return phase_done.get_objection_count(obj); + else begin + m_report_null_objection(obj, "" , 0, "get_objection_count"); + return 0; + end +endfunction : get_objection_count + +// sync +// ---- + +function void uvm_phase::sync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + if (!this.is_domain()) begin + `uvm_fatal("PH_BADSYNC","sync() called from a non-domain phase schedule node") + end + else if (target == null) begin + `uvm_fatal("PH_BADSYNC","sync() called with a null target domain") + end + else if (!target.is_domain()) begin + `uvm_fatal("PH_BADSYNC","sync() called with a non-domain phase schedule node as target") + end + else if (phase == null && with_phase != null) begin + `uvm_fatal("PH_BADSYNC","sync() called with null phase and non-null with phase") + end + else if (phase == null) begin + // whole domain sync - traverse this domain schedule from begin to end node and sync each node + int visited[uvm_phase]; + uvm_phase queue[$]; + queue.push_back(this); + visited[this] = 1; + while (queue.size()) begin + uvm_phase node; + node = queue.pop_front(); + if (node.m_imp != null) begin + sync(target, node.m_imp); + end + foreach (node.m_successors[succ]) begin + if (!visited.exists(succ)) begin + queue.push_back(succ); + visited[succ] = 1; + end + end + end + end else begin + // single phase sync + // this is a 2-way ('with') sync and we check first in case it is already there + uvm_phase from_node, to_node; + int found_to[$], found_from[$]; + if(with_phase == null) with_phase = phase; + from_node = find(phase); + to_node = target.find(with_phase); + if(from_node == null || to_node == null) return; + found_to = from_node.m_sync.find_index(node) with (node == to_node); + found_from = to_node.m_sync.find_index(node) with (node == from_node); + if (found_to.size() == 0) from_node.m_sync.push_back(to_node); + if (found_from.size() == 0) to_node.m_sync.push_back(from_node); + end +endfunction + + +// unsync +// ------ + +function void uvm_phase::unsync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + if (!this.is_domain()) begin + `uvm_fatal("PH_BADSYNC","unsync() called from a non-domain phase schedule node") + end else if (target == null) begin + `uvm_fatal("PH_BADSYNC","unsync() called with a null target domain") + end else if (!target.is_domain()) begin + `uvm_fatal("PH_BADSYNC","unsync() called with a non-domain phase schedule node as target") + end else if (phase == null && with_phase != null) begin + `uvm_fatal("PH_BADSYNC","unsync() called with null phase and non-null with phase") + end else if (phase == null) begin + // whole domain unsync - traverse this domain schedule from begin to end node and unsync each node + int visited[uvm_phase]; + uvm_phase queue[$]; + queue.push_back(this); + visited[this] = 1; + while (queue.size()) begin + uvm_phase node; + node = queue.pop_front(); + if (node.m_imp != null) unsync(target,node.m_imp); + foreach (node.m_successors[succ]) begin + if (!visited.exists(succ)) begin + queue.push_back(succ); + visited[succ] = 1; + end + end + end + end else begin + // single phase unsync + // this is a 2-way ('with') sync and we check first in case it is already there + uvm_phase from_node, to_node; + int found_to[$], found_from[$]; + if(with_phase == null) with_phase = phase; + from_node = find(phase); + to_node = target.find(with_phase); + if(from_node == null || to_node == null) return; + found_to = from_node.m_sync.find_index(node) with (node == to_node); + found_from = to_node.m_sync.find_index(node) with (node == from_node); + if (found_to.size()) from_node.m_sync.delete(found_to[0]); + if (found_from.size()) to_node.m_sync.delete(found_from[0]); + end +endfunction + + +// wait_for_state +//--------------- + +task uvm_phase::wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ); + case (op) + UVM_EQ: wait((state&m_state) != 0); + UVM_NE: wait((state&m_state) == 0); + UVM_LT: wait(m_state < state); + UVM_LTE: wait(m_state <= state); + UVM_GT: wait(m_state > state); + UVM_GTE: wait(m_state >= state); + endcase +endtask + + +//------------------------- +// Implementation - Jumping +//------------------------- + +// set_jump_phase +// ---- +// +// Specify a phase to transition to when phase is complete. + +function void uvm_phase::set_jump_phase(uvm_phase phase) ; + uvm_phase d; + + if ((m_state < UVM_PHASE_STARTED) || + (m_state > UVM_PHASE_ENDED) ) + begin + `uvm_error("JMPPHIDL", { "Attempting to jump from phase \"", + get_name(), "\" which is not currently active (current state is ", + m_state.name(), "). The jump will not happen until the phase becomes ", + "active."}) + end + + + + // A jump can be either forward or backwards in the phase graph. + // If the specified phase (name) is found in the set of predecessors + // then we are jumping backwards. If, on the other hand, the phase is in the set + // of successors then we are jumping forwards. If neither, then we + // have an error. + // + // If the phase is non-existant and thus we don't know where to jump + // we have a situation where the only thing to do is to uvm_report_fatal + // and terminate_phase. By calling this function the intent was to + // jump to some other phase. So, continuing in the current phase doesn't + // make any sense. And we don't have a valid phase to jump to. So we're done. + + d = m_find_predecessor(phase,0); + if (d == null) begin + d = m_find_successor(phase,0); + if (d == null) begin + string msg; + $sformat(msg,{"phase %s is neither a predecessor or successor of ", + "phase %s or is non-existant, so we cannot jump to it. ", + "Phase control flow is now undefined so the simulation ", + "must terminate"}, phase.get_name(), get_name()); + `uvm_fatal("PH_BADJUMP", msg) + end + else begin + m_jump_fwd = 1; + `uvm_info("PH_JUMPF",$sformatf("jumping forward to phase %s", phase.get_name()), + UVM_DEBUG) + end + end + else begin + m_jump_bkwd = 1; + `uvm_info("PH_JUMPB",$sformatf("jumping backward to phase %s", phase.get_name()), + UVM_DEBUG) + end + + m_jump_phase = d; +endfunction + +// end_prematurely +// ---- +// +// Set a flag to cause the phase to end prematurely. + +function void uvm_phase::end_prematurely() ; + m_premature_end = 1 ; +endfunction + +// jump +// ---- +// +// Note that this function does not directly alter flow of control. +// That is, the new phase is not initiated in this function. +// Rather, flags are set which execute_phase() uses to determine +// that a jump has been requested and performs the jump. + +function void uvm_phase::jump(uvm_phase phase); + set_jump_phase(phase) ; + end_prematurely() ; +endfunction + + +// jump_all +// -------- +function void uvm_phase::jump_all(uvm_phase phase); + `uvm_warning("NOTIMPL","uvm_phase::jump_all is not implemented and has been replaced by uvm_domain::jump_all") +endfunction + + +// get_jump_target +// --------------- + +function uvm_phase uvm_phase::get_jump_target(); + return m_jump_phase; +endfunction + + +// clear +// ----- +// for internal graph maintenance after a forward jump +function void uvm_phase::clear(uvm_phase_state state = UVM_PHASE_DORMANT); + uvm_objection phase_done; + phase_done = get_objection(); + m_state = state; + m_phase_proc = null; + if (phase_done != null) + phase_done.clear(this); +endfunction + + +// clear_successors +// ---------------- +// for internal graph maintenance after a forward jump +// - called only by execute_phase() +// - depth-first traversal of the DAG, calliing clear() on each node +// - do not clear the end phase or beyond +function void uvm_phase::clear_successors(uvm_phase_state state = UVM_PHASE_DORMANT, + uvm_phase end_state=null); + if(this == end_state) + return; + clear(state); + foreach(m_successors[succ]) begin + succ.clear_successors(state, end_state); + end +endfunction + + +//--------------------------------- +// Implementation - Overall Control +//--------------------------------- +// wait_for_self_and_siblings_to_drop +// ----------------------------- +// This task loops until this phase instance and all its siblings, either +// sync'd or sharing a common successor, have all objections dropped. +task uvm_phase::wait_for_self_and_siblings_to_drop() ; + bit need_to_check_all = 1 ; + uvm_root top; + uvm_coreservice_t cs; + bit siblings[uvm_phase]; + + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + get_predecessors_for_successors(siblings); + foreach (m_sync[i]) begin + siblings[m_sync[i]] = 1; + end + + while (need_to_check_all) begin + uvm_objection phase_done; + phase_done = get_objection(); + need_to_check_all = 0 ; //if all are dropped, we won't need to do this again + + // wait for own objections to drop + if ((phase_done != null) && (phase_done.get_objection_total(top) != 0)) begin + m_state = UVM_PHASE_EXECUTING ; + phase_done.wait_for(UVM_ALL_DROPPED, top); + need_to_check_all = 1 ; + end + + // now wait for siblings to drop + foreach(siblings[sib]) begin + uvm_objection sib_phase_done; + sib_phase_done = sib.get_objection(); + sib.wait_for_state(UVM_PHASE_EXECUTING, UVM_GTE); // sibling must be at least executing + if ((sib_phase_done != null) && (sib_phase_done.get_objection_total(top) != 0)) begin + m_state = UVM_PHASE_EXECUTING ; + sib_phase_done.wait_for(UVM_ALL_DROPPED, top); // sibling must drop any objection + need_to_check_all = 1 ; + end + end + end +endtask + +// kill +// ---- + +function void uvm_phase::kill(); + + `uvm_info("PH_KILL", {"killing phase '", get_name(),"'"}, UVM_DEBUG) + + if (m_phase_proc != null) begin + m_phase_proc.kill(); + m_phase_proc = null; + end + +endfunction + + +// kill_successors +// --------------- + +// Using a depth-first traversal, kill all the successor phases of the +// current phase. +function void uvm_phase::kill_successors(); + foreach (m_successors[succ]) + succ.kill_successors(); + kill(); +endfunction + + +// m_run_phases +// ------------ + +// This task contains the top-level process that owns all the phase +// processes. By hosting the phase processes here we avoid problems +// associated with phase processes related as parents/children +task uvm_phase::m_run_phases(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + // initiate by starting first phase in common domain + begin + uvm_phase ph = uvm_domain::get_common_domain(); + void'(m_phase_hopper.try_put(ph)); + end + + m_uvm_core_state=UVM_CORE_RUNNING; + forever begin + uvm_phase phase; + m_phase_hopper.get(phase); + fork + begin + phase.execute_phase(); + end + join_none + #0; // let the process start running + end +endtask + + +// terminate_phase +// --------------- + +function void uvm_phase::m_terminate_phase(); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.clear(this); +endfunction + + +// print_termination_state +// ----------------------- + +function void uvm_phase::m_print_termination_state(); + uvm_root top; + uvm_coreservice_t cs; + uvm_objection phase_done; + phase_done = get_objection(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (phase_done != null) begin + `uvm_info("PH_TERMSTATE", + $sformatf("phase %s outstanding objections = %0d", + get_name(), phase_done.get_objection_total(top)), + UVM_DEBUG) + end + else begin + `uvm_info("PH_TERMSTATE", + $sformatf("phase %s has no outstanding objections", + get_name()), + UVM_DEBUG) + end +endfunction + + diff --git a/test_regress/t/t_uvm/base/uvm_policy.svh b/test_regress/t/t_uvm/base/uvm_policy.svh new file mode 100644 index 0000000000..c8c5459205 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_policy.svh @@ -0,0 +1,187 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Synopsys, Inc. +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 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. +//---------------------------------------------------------------------- + +typedef class uvm_root; + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_policy +// +// The abstract uvm_policy class provides a common base from which all UVM policy classes derive +// Implementation as per Section 16.1 UVM Policy +//------------------------------------------------------------------------------ +// @uvm-ieee 1800.2-2017 auto 16.1.1 +virtual class uvm_policy extends uvm_object; + + +typedef enum { + NEVER, + STARTED, + FINISHED +} recursion_state_e; + + +local uvm_object m_extensions[uvm_object_wrapper]; +local uvm_object m_policy_stack[$]; + + + + +// Function -- NODOCS -- new +// +// Creates a policy with the specified instance name. If name is not provided, then the policy instance is +// unnamed. + +// @uvm-ieee 1800.2-2017 auto 16.1.2.1 +function new (string name=""); + super.new(name); +endfunction + +// Function -- NODOCS -- flush +// +// The flush method resets the internal state of the policy, such that it can be reused. +// Policy extensions are Not cleared in below method as per 16.1.2.3 +// @uvm-ieee 1800.2-2017 auto 16.1.2.2 +virtual function void flush(); + m_policy_stack.delete(); + +endfunction + + + +// Function -- NODOCS -- extension_exists +// Function extension_exists +// Returns 1 if an extension exists within the policy with type matching ext_type; otherwise, returns 0. +// @uvm-ieee 1800.2-2017 auto 16.1.2.3.1 +virtual function bit extension_exists( uvm_object_wrapper ext_type ); + + if (m_extensions.exists(ext_type)) + extension_exists = 1; + else + extension_exists = 0; + +endfunction + + +// Function -- NODOCS -- set_extension +// +// Sets the given extension inside of the policy, indexed using return value from extension's get_object_type? +// method (see 5.3.4.6). Only a single instance of an extension is stored per type. If there is an existing +// extension instance matching extension's type, extension replaces the instance and the replaced instance +// handle is returned; otherwise, null is returned. +// @uvm-ieee 1800.2-2017 auto 16.1.2.3.2 +virtual function uvm_object set_extension( uvm_object extension ); +uvm_object m_set_extension; + if ( extension == null) + uvm_report_fatal("NULLEXT", "Attempting to set null extension ", UVM_NONE); + + // Case where extension exists. + if(m_extensions.exists(extension.get_object_type())) begin + m_set_extension = m_extensions[extension.get_object_type()] ; + m_extensions[extension.get_object_type()] = extension; + return m_set_extension; + end + else begin + // Other case where extension doesnt exist. Nothing to return + m_extensions[extension.get_object_type()] = extension; + return null; + end + +endfunction + + +// Function -- NODOCS -- get_extension +//Returns the extension value stored within the policy with type matching ext_type. Returns null if no +// extension exists matching that type. +// @uvm-ieee 1800.2-2017 auto 16.1.2.3.3 +virtual function uvm_object get_extension(uvm_object_wrapper ext_type ); + if (m_extensions.exists(ext_type)) begin + return m_extensions[ext_type]; + end + else + return null; +endfunction + +// Function -- NODOCS -- clear_extension +// Removes the extension value stored within the policy matching type ext_type. If no extension exists +// matching type ext_type, the request is silently ignored. +// @uvm-ieee 1800.2-2017 auto 16.1.2.3.4 +virtual function void clear_extension( uvm_object_wrapper ext_type ); + m_extensions.delete(ext_type); +endfunction + +// Function -- NODOCS -- clear_extensions +// Removes all extensions currently stored within the policy. +// @uvm-ieee 1800.2-2017 auto 16.1.2.3.5 +virtual function void clear_extensions(); + m_extensions.delete(); +endfunction + + +// Function -- NODOCS -- push_active_object +// Pushes obj on to the internal object stack for this policy, making it the current active object, as retrieved by +// get_active_object (see 16.1.3.3). An implementation shall generate an error message if obj is null and the +// request will be ignored. Additionally, the policy shall push itself onto the active policy stack for obj using push_active_policy (see +// 5.3.14.1) when push_active_object is called. +// @uvm-ieee 1800.2-2017 auto 16.1.3.1 +virtual function void push_active_object( uvm_object obj ); + if(obj != null) + m_policy_stack.push_front(obj); + // Placeholder. Will be removed once uvm_object is updated. That's a seperate mantisi 6438 + // obj.push_active_policy(this); + // + else + `uvm_error("UVM_POLICY_PUSHNULL", "Attempting to push an null object push_active_object onto the policy stack") + +endfunction + +// Function -- NODOCS -- pop_active_object +// Pops the current active object off of the internal object stack for this policy and returns the popped off value. +// For additional behaviour descriptions (see +// 5.3.14.2) when pop_active_object is called. +// @uvm-ieee 1800.2-2017 auto 16.1.3.2 +virtual function uvm_object pop_active_object(); +uvm_object m_tmp; + if(m_policy_stack.size() != 0) begin + m_tmp = m_policy_stack.pop_front(); + return m_tmp; + end + else + `uvm_info("UVM_POLICY_EMPTY_POPACTIVE_OBJECT", "Attempting to pop an empty policy stack",UVM_DEBUG) + +endfunction + +// Function -- NODOCS -- get_active_object +// Returns the head of the internal object stack for this policy. +// empty, null is returned. +// @uvm-ieee 1800.2-2017 auto 16.1.3.3 +virtual function uvm_object get_active_object(); + if(m_policy_stack.size() != 0) + return m_policy_stack[0]; +endfunction + +// Function -- NODOCS -- get_active_object_depth +// Returns the current depth of the internal object stack for this policy. +virtual function int unsigned get_active_object_depth(); + return m_policy_stack.size(); +endfunction + +endclass + diff --git a/test_regress/t/t_uvm/base/uvm_pool.svh b/test_regress/t/t_uvm/base/uvm_pool.svh index ec687c966e..4cdfc6b361 100644 --- a/test_regress/t/t_uvm/base/uvm_pool.svh +++ b/test_regress/t/t_uvm/base/uvm_pool.svh @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 // //------------------------------------------------------------------------------ // Copyright 2007-2014 Mentor Graphics Corporation @@ -35,7 +34,6 @@ // be allocated on demand, and passed and stored by reference. //------------------------------------------------------------------------------ -//UVM ~ // @uvm-ieee 1800.2-2017 auto 11.2.1 class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; @@ -44,9 +42,9 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; static protected this_type m_global_pool; protected T pool[KEY]; -//UVM `uvm_object_param_utils(uvm_pool #(KEY,T)) -//UVM `uvm_type_name_decl("uvm_pool") - + `uvm_object_param_utils(uvm_pool #(KEY,T)) + `uvm_type_name_decl("uvm_pool") + // Function -- NODOCS -- new // // Creates a new pool with the given ~name~. @@ -59,7 +57,7 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; // Function -- NODOCS -- get_global_pool // - // Returns the singleton global pool for the item type, T. + // Returns the singleton global pool for the item type, T. // // This allows items to be shared amongst components throughout the // verification environment. @@ -73,12 +71,12 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; // Function -- NODOCS -- get_global // - // Returns the specified item instance from the global item pool. + // Returns the specified item instance from the global item pool. // @uvm-ieee 1800.2-2017 auto 11.2.2.3 static function T get_global (KEY key); this_type gpool; - gpool = get_global_pool(); + gpool = get_global_pool(); return gpool.get(key); endfunction @@ -98,7 +96,7 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; end return pool[key]; endfunction - + // Function -- NODOCS -- add // @@ -109,7 +107,7 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; virtual function void add (KEY key, T item); pool[key] = item; endfunction - + // Function -- NODOCS -- num // @@ -166,7 +164,7 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; // // Returns the key of the last item stored in the pool. // - // If the pool is empty, then 0 is returned and ~key~ is unchanged. + // If the pool is empty, then 0 is returned and ~key~ is unchanged. // // If the pool is not empty, then ~key~ is set to the last key in // the pool and 1 is returned. @@ -182,7 +180,7 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; // Returns the key of the next item in the pool. // // If the input ~key~ is the last key in the pool, then ~key~ is - // left unchanged and 0 is returned. + // left unchanged and 0 is returned. // // If a next key is found, then ~key~ is updated with that key // and 1 is returned. @@ -198,7 +196,7 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; // Returns the key of the previous item in the pool. // // If the input ~key~ is the first key in the pool, then ~key~ is - // left unchanged and 0 is returned. + // left unchanged and 0 is returned. // // If a previous key is found, then ~key~ is updated with that key // and 1 is returned. @@ -217,22 +215,22 @@ class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; pool = p.pool; endfunction -//UVM virtual function void do_print (uvm_printer printer); -//UVM string v; -//UVM int cnt; -//UVM string item; -//UVM KEY key; -//UVM printer.print_array_header("pool",pool.num(),"aa_object_string"); -//UVM if (pool.first(key)) -//UVM do begin -//UVM item.itoa(cnt); -//UVM item = {"[-key",item,"--]"}; -//UVM $swrite(v,pool[key]); -//UVM printer.print_generic(item,"",-1,v,"["); -//UVM end -//UVM while (pool.next(key)); -//UVM printer.print_array_footer(); -//UVM endfunction + virtual function void do_print (uvm_printer printer); + string v; + int cnt; + string item; + KEY key; + printer.print_array_header("pool",pool.num(),"aa_object_string"); + if (pool.first(key)) + do begin + item.itoa(cnt); + item = {"[-key",item,"--]"}; + $swrite(v,pool[key]); + printer.print_generic(item,"",-1,v,"["); + end + while (pool.next(key)); + printer.print_array_footer(); + endfunction endclass @@ -243,20 +241,19 @@ endclass // //------------------------------------------------------------------------------ // This provides a specialization of the generic class for -// an associative array of -based objects indexed by string. +// an associative array of -based objects indexed by string. // Specializations of this class include the ~uvm_event_pool~ (a // uvm_object_string_pool storing ~uvm_event#(uvm_object)~) and // ~uvm_barrier_pool~ (a uvm_obejct_string_pool storing ). //------------------------------------------------------------------------------ -// UVM ~ class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); typedef uvm_object_string_pool #(T) this_type; static protected this_type m_global_pool; -//UVM `uvm_object_param_utils(uvm_object_string_pool#(T)) -//UVM `uvm_type_name_decl("uvm_obj_str_pool") + `uvm_object_param_utils(uvm_object_string_pool#(T)) + `uvm_type_name_decl("uvm_obj_str_pool") // Function -- NODOCS -- new // @@ -268,7 +265,7 @@ class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); // Function -- NODOCS -- get_global_pool // - // Returns the singleton global pool for the item type, T. + // Returns the singleton global pool for the item type, T. // // This allows items to be shared amongst components throughout the // verification environment. @@ -282,11 +279,11 @@ class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); // Function -- NODOCS -- get_global // - // Returns the specified item instance from the global item pool. + // Returns the specified item instance from the global item pool. static function T get_global (string key); this_type gpool; - gpool = get_global_pool(); + gpool = get_global_pool(); return gpool.get(key); endfunction @@ -303,7 +300,7 @@ class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); pool[key] = new (key); return pool[key]; endfunction - + // Function -- NODOCS -- delete // @@ -321,15 +318,15 @@ class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); // Function- do_print -//UVM virtual function void do_print (uvm_printer printer); -//UVM string key; -//UVM printer.print_array_header("pool",pool.num(),"aa_object_string"); -//UVM if (pool.first(key)) -//UVM do -//UVM printer.print_object({"[",key,"]"}, pool[key],"["); -//UVM while (pool.next(key)); -//UVM printer.print_array_footer(); -//UVM endfunction + virtual function void do_print (uvm_printer printer); + string key; + printer.print_array_header("pool",pool.num(),"aa_object_string"); + if (pool.first(key)) + do + printer.print_object({"[",key,"]"}, pool[key],"["); + while (pool.next(key)); + printer.print_array_footer(); + endfunction endclass @@ -337,5 +334,5 @@ endclass typedef class uvm_barrier; typedef class uvm_event; -//UVM typedef uvm_object_string_pool #(uvm_barrier) uvm_barrier_pool /* @uvm-ieee 1800.2-2017 auto 10.4.2.1*/ ; -//UVM typedef uvm_object_string_pool #(uvm_event#(uvm_object)) uvm_event_pool /* @uvm-ieee 1800.2-2017 auto 10.4.1.1*/ ; +typedef uvm_object_string_pool #(uvm_barrier) uvm_barrier_pool /* @uvm-ieee 1800.2-2017 auto 10.4.2.1*/ ; +typedef uvm_object_string_pool #(uvm_event#(uvm_object)) uvm_event_pool /* @uvm-ieee 1800.2-2017 auto 10.4.1.1*/ ; diff --git a/test_regress/t/t_uvm/base/uvm_port_base.svh b/test_regress/t/t_uvm/base/uvm_port_base.svh new file mode 100644 index 0000000000..97eb4a16c1 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_port_base.svh @@ -0,0 +1,838 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2018 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Semifore +// Copyright 2014 Intel Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2012-2017 Cisco Systems, Inc. +// Copyright 2017 Verific +// 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. +//------------------------------------------------------------------------------ + +const int UVM_UNBOUNDED_CONNECTIONS = -1; +const string s_connection_error_id = "Connection Error"; +const string s_connection_warning_id = "Connection Warning"; +const string s_spaces = " "; + +typedef class uvm_port_component_base; + + +// TITLE: Port Base Classes +// + + +// +// CLASS: uvm_port_list +// +// Associative array of uvm_port_component_base class handles, indexed by string +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + +typedef uvm_port_component_base uvm_port_list[string]; + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_port_component_base +// +//------------------------------------------------------------------------------ +// This class defines an interface for obtaining a port's connectivity lists +// after or during the end_of_elaboration phase. The sub-class, +// , implements this interface. +// +// Each port's full name and type name can be retrieved using ~get_full_name~ +// and ~get_type_name~ methods inherited from . +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 +//------------------------------------------------------------------------------ + +virtual class uvm_port_component_base extends uvm_component; + + function new (string name, uvm_component parent); + super.new(name,parent); + endfunction + + // Function: get_connected_to + // + // For a port or export type, this function fills ~list~ with all + // of the ports, exports and implementations that this port is + // connected to. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + pure virtual function void get_connected_to(ref uvm_port_list list); + + // Function -- NODOCS -- is_port + // + pure virtual function bit is_port(); + + // Function -- NODOCS -- is_export + // + pure virtual function bit is_export(); + + // Function -- NODOCS -- is_imp + // + // These function determine the type of port. The functions are + // mutually exclusive; one will return 1 and the other two will + // return 0. + + pure virtual function bit is_imp(); + + // Turn off auto config by not calling build_phase() + virtual function bit use_automatic_config(); + return 0; + endfunction : use_automatic_config + + virtual task do_task_phase (uvm_phase phase); + endtask +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_port_component #(PORT) +// +//------------------------------------------------------------------------------ +// This implementation of uvm_port_component class from IEEE 1800.2 declares all the +// API described in the LRM, plus it inherits from uvm_port_component_base for the +// purpose of providing the get_connected_to() method. +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 +//------------------------------------------------------------------------------ +class uvm_port_component #(type PORT=uvm_object) extends uvm_port_component_base; + + PORT m_port; + + function new (string name, uvm_component parent, PORT port); + super.new(name,parent); + if (port == null) + uvm_report_fatal("Bad usage", "Null handle to port", UVM_NONE); + m_port = port; + endfunction + + virtual function string get_type_name(); + if(m_port == null) return "uvm_port_component"; + return m_port.get_type_name(); + endfunction + + virtual function void resolve_bindings(); + m_port.resolve_bindings(); + endfunction + + // Function -- NODOCS -- get_port + // + // Retrieve the actual port object that this proxy refers to. + + function PORT get_port(); + return m_port; + endfunction + + // Function: get_connected_to + // + // Implementation of the pure function declared in uvm_port_component_base + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + virtual function void get_connected_to(ref uvm_port_list list); + PORT list1[string]; + m_port.get_connected_to(list1); + list.delete(); + foreach(list1[name]) begin + list[name] = list1[name].get_comp(); + end + endfunction + + function bit is_port (); + return m_port.is_port(); + endfunction + + function bit is_export (); + return m_port.is_export(); + endfunction + + function bit is_imp (); + return m_port.is_imp(); + endfunction + +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_port_base #(IF) +// +//------------------------------------------------------------------------------ +// +// Transaction-level communication between components is handled via its ports, +// exports, and imps, all of which derive from this class. +// +// The uvm_port_base extends IF, which is the type of the interface implemented +// by derived port, export, or implementation. IF is also a type parameter to +// uvm_port_base. +// +// IF - The interface type implemented by the subtype to this base port +// +// The UVM provides a complete set of ports, exports, and imps to enable transaction-level communication between entities. +// They can be found in the ../src/tlm*/ directory. See Section 12.1 of the IEEE Spec for details. +// +// Just before , an internal +// process occurs, after which each port and +// export holds a list of all imps connected to it via hierarchical connections +// to other ports and exports. In effect, we are collapsing the port's fanout, +// which can span several levels up and down the component hierarchy, into a +// single array held local to the port. Once the list is determined, the port's +// min and max connection settings can be checked and enforced. +// +// uvm_port_base possesses the properties of components in that they have a +// hierarchical instance path and parent. Because SystemVerilog does not support +// multiple inheritance, uvm_port_base cannot extend both the interface it +// implements and . Thus, uvm_port_base contains a local instance +// of uvm_component, to which it delegates such commands as get_name, +// get_full_name, and get_parent. +// The connectivity lists are returned in the form of handles to objects of this +// type. This allowing traversal of any port's fan-out and fan-in network +// through recursive calls to and . +// +//------------------------------------------------------------------------------ + +// Class: uvm_port_base +// The library implements the following public API beyond what is documented +// in 1800.2. + +// @uvm-ieee 1800.2-2017 auto 5.5.1 +virtual class uvm_port_base #(type IF=uvm_void) extends IF; + + + typedef uvm_port_base #(IF) this_type; + + // local, protected, and non-user properties + protected int unsigned m_if_mask; + protected this_type m_if; // REMOVE + protected int unsigned m_def_index; + uvm_port_component #(this_type) m_comp; + local this_type m_provided_by[string]; + local this_type m_provided_to[string]; + local uvm_port_type_e m_port_type; + local int m_min_size; + local int m_max_size; + local bit m_resolved; + local this_type m_imp_list[string]; + + // Function -- NODOCS -- new + // + // The first two arguments are the normal constructor + // arguments. + // + // The ~port_type~ can be one of , , or + // . + // + // The ~min_size~ and ~max_size~ specify the minimum and maximum number of + // implementation (imp) ports that must be connected to this port base by the + // end of elaboration. Setting ~max_size~ to ~UVM_UNBOUNDED_CONNECTIONS~ sets no + // maximum, i.e., an unlimited number of connections are allowed. + // + // By default, the parent/child relationship of any port being connected to + // this port is not checked. This can be overridden by configuring the + // port's ~check_connection_relationships~ bit via ~uvm_config_int::set()~. See + // for more information. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.1 + function new (string name, + uvm_component parent, + uvm_port_type_e port_type, + int min_size=0, + int max_size=1); + uvm_component comp; + int tmp; + m_port_type = port_type; + m_min_size = min_size; + m_max_size = max_size; + m_comp = new(name, parent, this); + + if (!uvm_config_int::get(m_comp, "", "check_connection_relationships",tmp)) + m_comp.set_report_id_action(s_connection_warning_id, UVM_NO_ACTION); + + endfunction + + + // Function -- NODOCS -- get_name + // + // Returns the leaf name of this port. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.2 + function string get_name(); + return m_comp.get_name(); + endfunction + + + // Function -- NODOCS -- get_full_name + // + // Returns the full hierarchical name of this port. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.3 + virtual function string get_full_name(); + return m_comp.get_full_name(); + endfunction + + + // Function -- NODOCS -- get_parent + // + // Returns the handle to this port's parent, or ~null~ if it has no parent. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.4 + virtual function uvm_component get_parent(); + return m_comp.get_parent(); + endfunction + + + // Function: get_comp + // + // Returns a handle to the internal proxy component representing this port. + // + // Ports are considered components. However, they do not inherit + // . Instead, they contain an instance of + // that serves as a proxy to this port. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + virtual function uvm_port_component_base get_comp(); + return m_comp; + endfunction + + + // Function -- NODOCS -- get_type_name + // + // Returns the type name to this port. Derived port classes must implement + // this method to return the concrete type. Otherwise, only a generic + // "uvm_port", "uvm_export" or "uvm_implementation" is returned. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.5 + virtual function string get_type_name(); + case( m_port_type ) + UVM_PORT : return "port"; + UVM_EXPORT : return "export"; + UVM_IMPLEMENTATION : return "implementation"; + endcase + endfunction + + + // Function -- NODOCS -- min_size + // + // Returns the minimum number of implementation ports that must + // be connected to this port by the end_of_elaboration phase. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.7 + function int max_size (); + return m_max_size; + endfunction + + + // Function -- NODOCS -- max_size + // + // Returns the maximum number of implementation ports that must + // be connected to this port by the end_of_elaboration phase. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.6 + function int min_size (); + return m_min_size; + endfunction + + + // Function -- NODOCS -- is_unbounded + // + // Returns 1 if this port has no maximum on the number of implementation + // ports this port can connect to. A port is unbounded when the ~max_size~ + // argument in the constructor is specified as ~UVM_UNBOUNDED_CONNECTIONS~. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.8 + function bit is_unbounded (); + return (m_max_size == UVM_UNBOUNDED_CONNECTIONS); + endfunction + + + // Function -- NODOCS -- is_port + + // @uvm-ieee 1800.2-2017 auto 5.5.2.11 + function bit is_port (); + return m_port_type == UVM_PORT; + endfunction + + // Function -- NODOCS -- is_export + + // @uvm-ieee 1800.2-2017 auto 5.5.2.11 + function bit is_export (); + return m_port_type == UVM_EXPORT; + endfunction + + // Function -- NODOCS -- is_imp + // + // Returns 1 if this port is of the type given by the method name, + // 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.11 + function bit is_imp (); + return m_port_type == UVM_IMPLEMENTATION; + endfunction + + + // Function -- NODOCS -- size + // + // Gets the number of implementation ports connected to this port. The value + // is not valid before the end_of_elaboration phase, as port connections have + // not yet been resolved. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.12 + function int size (); + return m_imp_list.num(); + endfunction + + + function void set_if (int index=0); + m_if = get_if(index); + if (m_if != null) + m_def_index = index; + endfunction + + function int m_get_if_mask(); + return m_if_mask; + endfunction + + + // Function -- NODOCS -- set_default_index + // + // Sets the default implementation port to use when calling an interface + // method. This method should only be called on UVM_EXPORT types. The value + // must not be set before the end_of_elaboration phase, when port connections + // have not yet been resolved. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.13 + function void set_default_index (int index); + m_def_index = index; + endfunction + + + // Function -- NODOCS -- connect + // + // Connects this port to the given ~provider~ port. The ports must be + // compatible in the following ways + // + // - Their type parameters must match + // + // - The ~provider~'s interface type (blocking, non-blocking, analysis, etc.) + // must be compatible. Each port has an interface mask that encodes the + // interface(s) it supports. If the bitwise AND of these masks is equal to + // the this port's mask, the requirement is met and the ports are + // compatible. For example, a uvm_blocking_put_port #(T) is compatible with + // a uvm_put_export #(T) and uvm_blocking_put_imp #(T) because the export + // and imp provide the interface required by the uvm_blocking_put_port. + // + // - Ports of type can only connect to other exports or imps. + // + // - Ports of type cannot be connected, as they are + // bound to the component that implements the interface at time of + // construction. + // + // In addition to type-compatibility checks, the relationship between this + // port and the ~provider~ port will also be checked if the port's + // ~check_connection_relationships~ configuration has been set. (See + // for more information.) + // + // Relationships, when enabled, are checked are as follows: + // + // - If this port is an UVM_PORT type, the ~provider~ can be a parent port, + // or a sibling export or implementation port. + // + // - If this port is a type, the provider can be a child + // export or implementation port. + // + // If any relationship check is violated, a warning is issued. + // + // Note- the method is related to but not the same + // as this method. The component's ~connect~ method is a phase callback where + // port's ~connect~ method calls are made. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.14 + virtual function void connect (this_type provider); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (end_of_elaboration_ph.get_state() == UVM_PHASE_EXECUTING || // TBD tidy + end_of_elaboration_ph.get_state() == UVM_PHASE_DONE ) begin + m_comp.uvm_report_warning("Late Connection", + {"Attempt to connect ",this.get_full_name()," (of type ",this.get_type_name(), + ") at or after end_of_elaboration phase. Ignoring."}); + return; + end + + if (provider == null) begin + m_comp.uvm_report_error(s_connection_error_id, + "Cannot connect to null port handle", UVM_NONE); + return; + end + + if (provider == this) begin + m_comp.uvm_report_error(s_connection_error_id, + "Cannot connect a port instance to itself", UVM_NONE); + return; + end + + if ((provider.m_if_mask & m_if_mask) != m_if_mask) begin + m_comp.uvm_report_error(s_connection_error_id, + {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") does not provide the complete interface required of this port (type ", + get_type_name(),")"}, UVM_NONE); + return; + end + + // IMP.connect(anything) is illegal + if (is_imp()) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf( +"Cannot call an imp port's connect method. An imp is connected only to the component passed in its constructor. (You attempted to bind this imp to %s)", provider.get_full_name()), UVM_NONE); + return; + end + + // EXPORT.connect(PORT) are illegal + if (is_export() && provider.is_port()) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf( +"Cannot connect exports to ports Try calling port.connect(export) instead. (You attempted to bind this export to %s).", provider.get_full_name()), UVM_NONE); + return; + end + + void'(m_check_relationship(provider)); + + m_provided_by[provider.get_full_name()] = provider; + provider.m_provided_to[get_full_name()] = this; + + endfunction + + + // Function: debug_connected_to + // + // The ~debug_connected_to~ method outputs a visual text display of the + // port/export/imp network to which this port connects (i.e., the port's + // fanout). + // + // This method must not be called before the end_of_elaboration phase, as port + // connections are not resolved until then. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + function void debug_connected_to (int level=0, int max_level=-1); + int sz, num, curr_num; + string s_sz; + static string indent, save; + this_type port; + + if (level < 0) level = 0; + if (level == 0) begin save = ""; indent=" "; end + + if (max_level != -1 && level >= max_level) + return; + + num = m_provided_by.num(); + + if (m_provided_by.num() != 0) begin + foreach (m_provided_by[nm]) begin + curr_num++; + port = m_provided_by[nm]; + save = {save, indent, " | \n"}; + save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; + indent = (num > 1 && curr_num != num) ? {indent," | "}:{indent, " "}; + port.debug_connected_to(level+1, max_level); + indent = indent.substr(0,indent.len()-4-1); + end + end + + if (level == 0) begin + if (save != "") + save = {"This port's fanout network:\n\n ", + get_full_name()," (",get_type_name(),")\n",save,"\n"}; + if (m_imp_list.num() == 0) begin + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (end_of_elaboration_ph.get_state() == UVM_PHASE_EXECUTING || + end_of_elaboration_ph.get_state() == UVM_PHASE_DONE ) // TBD tidy + save = {save," Connected implementations: none\n"}; + else + save = {save, + " Connected implementations: not resolved until end-of-elab\n"}; + end + else begin + save = {save," Resolved implementation list:\n"}; + foreach (m_imp_list[nm]) begin + port = m_imp_list[nm]; + s_sz.itoa(sz); + save = {save, indent, s_sz, ": ",nm," (",port.get_type_name(),")\n"}; + sz++; + end + end + m_comp.uvm_report_info("debug_connected_to", save); + end + endfunction + + + // Function: debug_provided_to + // + // The ~debug_provided_to~ method outputs a visual display of the port/export + // network that ultimately connect to this port (i.e., the port's fanin). + // + // This method must not be called before the end_of_elaboration phase, as port + // connections are not resolved until then. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + function void debug_provided_to (int level=0, int max_level=-1); + string nm; + int num,curr_num; + this_type port; + static string indent, save; + + if (level < 0) level = 0; + if (level == 0) begin save = ""; indent = " "; end + + if (max_level != -1 && level > max_level) + return; + + num = m_provided_to.num(); + + if (num != 0) begin + foreach (m_provided_to[nm]) begin + curr_num++; + port = m_provided_to[nm]; + save = {save, indent, " | \n"}; + save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; + indent = (num > 1 && curr_num != num) ? {indent," | "}:{indent, " "}; + port.debug_provided_to(level+1, max_level); + indent = indent.substr(0,indent.len()-4-1); + end + end + + if (level == 0) begin + if (save != "") + save = {"This port's fanin network:\n\n ", + get_full_name()," (",get_type_name(),")\n",save,"\n"}; + if (m_provided_to.num() == 0) + save = {save,indent,"This port has not been bound\n"}; + m_comp.uvm_report_info("debug_provided_to", save); + end + + endfunction + + + // get_connected_to + // ---------------- + + // @uvm-ieee 1800.2-2017 auto 5.5.2.9 + function void get_connected_to (ref uvm_port_base #(IF) list[string]); + this_type port; + list.delete(); + foreach (m_provided_by[name]) begin + port = m_provided_by[name]; + list[name] = port; + end + endfunction + + + // get_provided_to + // --------------- + + // @uvm-ieee 1800.2-2017 auto 5.5.2.10 + function void get_provided_to (ref uvm_port_base #(IF) list[string]); + this_type port; + list.delete(); + foreach (m_provided_to[name]) begin + port = m_provided_to[name]; + list[name] = port; + end + endfunction + + + // m_check_relationship + // -------------------- + + local function bit m_check_relationship (this_type provider); + string s; + this_type from; + uvm_component from_parent; + uvm_component to_parent; + uvm_component from_gparent; + uvm_component to_gparent; + + // Checks that the connection is between ports that are hierarchically + // adjacent (up or down one level max, or are siblings), + // and check for legal direction, requirer.connect(provider). + + // if we're an analysis port, allow connection to anywhere + if (get_type_name() == "uvm_analysis_port") + return 1; + + from = this; + from_parent = get_parent(); + to_parent = provider.get_parent(); + + // skip check if we have a parentless port + if (from_parent == null || to_parent == null) + return 1; + + from_gparent = from_parent.get_parent(); + to_gparent = to_parent.get_parent(); + + // Connecting port-to-port: CHILD.port.connect(PARENT.port) + // + if (from.is_port() && provider.is_port() && from_gparent != to_parent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not up one level of hierarchy from this port. ", + "A port-to-port connection takes the form ", + "child_component.child_port.connect(parent_port)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + + // Connecting port-to-export: SIBLING.port.connect(SIBLING.export) + // Connecting port-to-imp: SIBLING.port.connect(SIBLING.imp) + // + else if (from.is_port() && (provider.is_export() || provider.is_imp()) && + from_gparent != to_gparent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not at the same level of hierarchy as this port. ", + "A port-to-export connection takes the form ", + "component1.port.connect(component2.export)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + + // Connecting export-to-export: PARENT.export.connect(CHILD.export) + // Connecting export-to-imp: PARENT.export.connect(CHILD.imp) + // + else if (from.is_export() && (provider.is_export() || provider.is_imp()) && + from_parent != to_gparent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not down one level of hierarchy from this export. ", + "An export-to-export or export-to-imp connection takes the form ", + "parent_export.connect(child_component.child_export)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + + return 1; + endfunction + + + // m_add_list + // + // Internal method. + + local function void m_add_list (this_type provider); + string sz; + this_type imp; + + for (int i = 0; i < provider.size(); i++) begin + imp = provider.get_if(i); + if (!m_imp_list.exists(imp.get_full_name())) + m_imp_list[imp.get_full_name()] = imp; + end + + endfunction + + + // Function -- NODOCS -- resolve_bindings + // + // This callback is called just before entering the end_of_elaboration phase. + // It recurses through each port's fanout to determine all the imp + // destinations. It then checks against the required min and max connections. + // After resolution, returns a valid value and + // can be used to access a particular imp. + // + // This method is automatically called just before the start of the + // end_of_elaboration phase. Users should not need to call it directly. + + // @uvm-ieee 1800.2-2017 auto 5.5.2.15 + virtual function void resolve_bindings(); + if (m_resolved) // don't repeat ourselves + return; + + if (is_imp()) begin + m_imp_list[get_full_name()] = this; + end + else begin + foreach (m_provided_by[nm]) begin + this_type port; + port = m_provided_by[nm]; + port.resolve_bindings(); + m_add_list(port); + end + end + + m_resolved = 1; + + if (size() < min_size() ) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf("connection count of %0d does not meet required minimum of %0d", + size(), min_size()), UVM_NONE); + end + + if (max_size() != UVM_UNBOUNDED_CONNECTIONS && size() > max_size() ) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf("connection count of %0d exceeds maximum of %0d", + size(), max_size()), UVM_NONE); + end + + if (size()) + set_if(0); + + endfunction + + + // Function -- NODOCS -- get_if + // + // Returns the implementation (imp) port at the given index from the array of + // imps this port is connected to. Use to get the valid range for index. + // This method can only be called at the end_of_elaboration phase or after, as + // port connections are not resolved before then. + + function uvm_port_base #(IF) get_if(int index=0); + string s; + if (size()==0) begin + m_comp.uvm_report_warning("get_if", + "Port size is zero; cannot get interface at any index", UVM_NONE); + return null; + end + if (index < 0 || index >= size()) begin + $sformat(s, "Index %0d out of range [0,%0d]", index, size()-1); + m_comp.uvm_report_warning(s_connection_error_id, s, UVM_NONE); + return null; + end + foreach (m_imp_list[nm]) begin + if (index == 0) + return m_imp_list[nm]; + index--; + end + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_printer.svh b/test_regress/t/t_uvm/base/uvm_printer.svh new file mode 100644 index 0000000000..1b636abbee --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_printer.svh @@ -0,0 +1,1902 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2018 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2018 Qualcomm, Inc. +// Copyright 2014 Intel Corporation +// Copyright 2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014-2018 Cisco Systems, 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 or the specific language governing +// permissions and limitations under the License. +//------------------------------------------------------------------------------ + + +typedef class m_uvm_printer_knobs; +typedef class uvm_printer_element; +typedef class uvm_structure_proxy; + +`ifdef UVM_ENABLE_DEPRECATED_API +typedef struct { + int level; + string name; + string type_name; + string size; + string val; +} uvm_printer_row_info; +`endif + +// File: uvm_printer + +// @uvm-ieee 1800.2-2017 auto 16.2.1 +virtual class uvm_printer extends uvm_policy; + + `uvm_object_abstract_utils(uvm_printer) + + extern function new(string name="") ; + + bit m_flushed ; // 0 = needs flush, 1 = flushed since last use + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- knobs + // + // The knob object provides access to the variety of knobs associated with a + // specific printer instance. + // + m_uvm_printer_knobs knobs ; +`else + //config values from set_* accessors are stored in knobs + local m_uvm_printer_knobs knobs ; +`endif + +protected function m_uvm_printer_knobs get_knobs() ; return knobs; endfunction + + // Group -- NODOCS -- Methods for printer usage + + // These functions are called from , or they are called + // directly on any data to get formatted printing. + + extern static function void set_default(uvm_printer printer) ; + + extern static function uvm_printer get_default() ; + + // Function -- NODOCS -- print_field + // + // Prints an integral field (up to 4096 bits). + // + // name - The name of the field. + // value - The value of the field. + // size - The number of bits of the field (maximum is 4096). + // radix - The radix to use for printing. The printer knob for radix is used + // if no radix is specified. + // scope_separator - is used to find the leaf name since many printers only + // print the leaf name of a field. Typical values for the separator + // are . (dot) or [ (open bracket). + + // @uvm-ieee 1800.2-2017 auto 16.2.3.8 + extern virtual function void print_field (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + +`ifdef UVM_ENABLE_DEPRECATED_API + // backward compatibility + virtual function void print_int (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + print_field (name, value, size, radix, scope_separator, type_name); + endfunction +`endif + + // @uvm-ieee 1800.2-2017 auto 16.2.3.9 + extern virtual function void print_field_int (string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + + // Function -- NODOCS -- print_object + // + // Prints an object. Whether the object is recursed depends on a variety of + // knobs, such as the depth knob; if the current depth is at or below the + // depth setting, then the object is not recursed. + // + // By default, the children of are printed. To turn this + // behavior off, you must set the bit to 0 for + // the specific children you do not want automatically printed. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.1 + extern virtual function void print_object (string name, + uvm_object value, + byte scope_separator="."); + + + extern virtual function void print_object_header (string name, + uvm_object value, + byte scope_separator="."); + + + // Function -- NODOCS -- print_string + // + // Prints a string field. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.10 + extern virtual function void print_string (string name, + string value, + byte scope_separator="."); + + uvm_policy::recursion_state_e m_recur_states[uvm_object][uvm_recursion_policy_enum /*recursion*/] ; + + // @uvm-ieee 1800.2-2017 auto 16.2.3.2 + extern virtual function uvm_policy::recursion_state_e object_printed ( uvm_object value, + uvm_recursion_policy_enum recursion); + + // Function -- NODOCS -- print_time + // + // Prints a time value. name is the name of the field, and value is the + // value to print. + // + // The print is subject to the ~$timeformat~ system task for formatting time + // values. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.11 + extern virtual function void print_time (string name, + time value, + byte scope_separator="."); + + + // Function -- NODOCS -- print_real + // + // Prints a real field. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.12 + extern virtual function void print_real (string name, + real value, + byte scope_separator="."); + + // Function -- NODOCS -- print_generic + // + // Prints a field having the given ~name~, ~type_name~, ~size~, and ~value~. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.3 + extern virtual function void print_generic (string name, + string type_name, + int size, + string value, + byte scope_separator="."); + + // @uvm-ieee 1800.2-2017 auto 16.2.3.4 + extern virtual function void print_generic_element (string name, + string type_name, + string size, + string value); + + // Group -- NODOCS -- Methods for printer subtyping + + // Function -- NODOCS -- emit + // + // Emits a string representing the contents of an object + // in a format defined by an extension of this object. + + extern virtual function string emit (); + + extern virtual function void flush (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.1 + extern virtual function void set_name_enabled (bit enabled); + // @uvm-ieee 1800.2-2017 auto 16.2.5.1 + extern virtual function bit get_name_enabled (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.2 + extern virtual function void set_type_name_enabled (bit enabled); + // @uvm-ieee 1800.2-2017 auto 16.2.5.2 + extern virtual function bit get_type_name_enabled (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.3 + extern virtual function void set_size_enabled (bit enabled); + // @uvm-ieee 1800.2-2017 auto 16.2.5.3 + extern virtual function bit get_size_enabled (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.4 + extern virtual function void set_id_enabled (bit enabled); + // @uvm-ieee 1800.2-2017 auto 16.2.5.4 + extern virtual function bit get_id_enabled (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.5 + extern virtual function void set_radix_enabled (bit enabled); + // @uvm-ieee 1800.2-2017 auto 16.2.5.5 + extern virtual function bit get_radix_enabled (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.6 + extern virtual function void set_radix_string (uvm_radix_enum radix, string prefix); + // @uvm-ieee 1800.2-2017 auto 16.2.5.6 + extern virtual function string get_radix_string (uvm_radix_enum radix); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.7 + extern virtual function void set_default_radix (uvm_radix_enum radix); + // @uvm-ieee 1800.2-2017 auto 16.2.5.7 + extern virtual function uvm_radix_enum get_default_radix (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.8 + extern virtual function void set_root_enabled (bit enabled); + // @uvm-ieee 1800.2-2017 auto 16.2.5.8 + extern virtual function bit get_root_enabled (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.9 + extern virtual function void set_recursion_policy (uvm_recursion_policy_enum policy); + // @uvm-ieee 1800.2-2017 auto 16.2.5.9 + extern virtual function uvm_recursion_policy_enum get_recursion_policy (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.10 + extern virtual function void set_max_depth (int depth); + // @uvm-ieee 1800.2-2017 auto 16.2.5.10 + extern virtual function int get_max_depth (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.11 + extern virtual function void set_file (UVM_FILE fl); + // @uvm-ieee 1800.2-2017 auto 16.2.5.11 + extern virtual function UVM_FILE get_file (); + + // @uvm-ieee 1800.2-2017 auto 16.2.5.12 + extern virtual function void set_line_prefix (string prefix); + // @uvm-ieee 1800.2-2017 auto 16.2.5.12 + extern virtual function string get_line_prefix (); + + // @uvm-ieee 1800.2-2017 auto 16.2.6 + extern virtual function void set_begin_elements (int elements = 5); + // @uvm-ieee 1800.2-2017 auto 16.2.6 + extern virtual function int get_begin_elements (); + // @uvm-ieee 1800.2-2017 auto 16.2.6 + extern virtual function void set_end_elements (int elements = 5); + // @uvm-ieee 1800.2-2017 auto 16.2.6 + extern virtual function int get_end_elements (); + + local uvm_printer_element m_element_stack[$] ; + + protected function int m_get_stack_size(); return m_element_stack.size(); endfunction + + // @uvm-ieee 1800.2-2017 auto 16.2.7.1 + extern protected virtual function uvm_printer_element get_bottom_element (); + + // @uvm-ieee 1800.2-2017 auto 16.2.7.2 + extern protected virtual function uvm_printer_element get_top_element (); + + // @uvm-ieee 1800.2-2017 auto 16.2.7.3 + extern virtual function void push_element ( string name, + string type_name, + string size, + string value="" + ); + + // @uvm-ieee 1800.2-2017 auto 16.2.7.4 + extern virtual function void pop_element (); + + // return an element from the recycled stack if available or a new one otherwise + extern function uvm_printer_element get_unused_element() ; + + // store element instances that have been created but are not currently on the stack + uvm_printer_element m_recycled_elements[$]; + +`ifdef UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- format_row + // + // Hook for producing custom output of a single field (row). + // + extern virtual function string format_row (uvm_printer_row_info row); + + + // Function -- NODOCS -- format_header + // + // Hook to override base header with a custom header. + virtual function string format_header(); + return ""; + endfunction + + + // Function -- NODOCS -- format_footer + // + // Hook to override base footer with a custom footer. + virtual function string format_footer(); + return ""; + endfunction + + + // Function -- NODOCS -- adjust_name + // + // Prints a field's name, or ~id~, which is the full instance name. + // + // The intent of the separator is to mark where the leaf name starts if the + // printer if configured to print only the leaf name of the identifier. + + extern virtual protected function string adjust_name (string id, + byte scope_separator="."); +`endif + + // Function -- NODOCS -- print_array_header + // + // Prints the header of an array. This function is called before each + // individual element is printed. is called to mark the + // completion of array printing. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.5 + extern virtual function void print_array_header(string name, + int size, + string arraytype="array", + byte scope_separator="."); + + // Function -- NODOCS -- print_array_range + // + // Prints a range using ellipses for values. This method is used when honoring + // the array knobs for partial printing of large arrays, + // and . + // + // This function should be called after begin_elements have been printed + // and before end_elements have been printed. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.6 + extern virtual function void print_array_range (int min, int max); + + + // Function -- NODOCS -- print_array_footer + // + // Prints the header of a footer. This function marks the end of an array + // print. Generally, there is no output associated with the array footer, but + // this method let's the printer know that the array printing is complete. + + // @uvm-ieee 1800.2-2017 auto 16.2.3.7 + extern virtual function void print_array_footer (int size = 0); + + + + // Utility methods + extern function bit istop (); + extern function string index_string (int index, string name=""); + + string m_string; + +endclass + +// @uvm-ieee 1800.2-2017 auto 16.2.8.1 +class uvm_printer_element extends uvm_object; + + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.1 + extern function new (string name=""); + + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.2 + extern virtual function void set (string element_name = "", + string element_type_name = "", + string element_size = "", + string element_value = "" + ); + + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.3 + extern virtual function void set_element_name (string element_name); + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.3 + extern virtual function string get_element_name (); + + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.4 + extern virtual function void set_element_type_name (string element_type_name); + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.4 + extern virtual function string get_element_type_name (); + + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.5 + extern virtual function void set_element_size (string element_size); + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.5 + extern virtual function string get_element_size (); + + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.6 + extern virtual function void set_element_value (string element_value); + // @uvm-ieee 1800.2-2017 auto 16.2.8.2.6 + extern virtual function string get_element_value (); + + extern function void add_child(uvm_printer_element child) ; + extern function void get_children(ref uvm_printer_element children[$], input bit recurse) ; + extern function void clear_children() ; + + local string m_name ; + local string m_type_name ; + local string m_size ; + local string m_value ; + local uvm_printer_element m_children[$] ; +endclass + +// @uvm-ieee 1800.2-2017 auto 16.2.9.1 +class uvm_printer_element_proxy extends uvm_structure_proxy#(uvm_printer_element); + // @uvm-ieee 1800.2-2017 auto 16.2.9.2.1 + extern function new (string name=""); + // @uvm-ieee 1800.2-2017 auto 16.2.9.2.2 + extern virtual function void get_immediate_children(uvm_printer_element s, ref uvm_printer_element children[$]); +endclass : uvm_printer_element_proxy + + +//------------------------------------------------------------------------------ +// +// Class: uvm_table_printer +// +// The table printer prints output in a tabular format. +// +// The following shows sample output from the table printer. +// +//| --------------------------------------------------- +//| Name Type Size Value +//| --------------------------------------------------- +//| c1 container - @1013 +//| d1 mydata - @1022 +//| v1 integral 32 'hcb8f1c97 +//| e1 enum 32 THREE +//| str string 2 hi +//| value integral 12 'h2d +//| --------------------------------------------------- +// +//------------------------------------------------------------------------------ +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + +// @uvm-ieee 1800.2-2017 auto 16.2.10.1 +class uvm_table_printer extends uvm_printer; + + // @uvm-ieee 1800.2-2017 auto 16.2.10.2.2 + `uvm_object_utils(uvm_table_printer) + + + // @uvm-ieee 1800.2-2017 auto 16.2.10.2.1 + extern function new(string name=""); + + // Function -- NODOCS -- emit + // + // Formats the collected information from prior calls to ~print_*~ + // into table format. + // + extern virtual function string emit(); + + extern virtual function string m_emit_element(uvm_printer_element element, int unsigned level); + + local static uvm_table_printer m_default_table_printer ; + + local static string m_space ; + + // @uvm-ieee 1800.2-2017 auto 16.2.10.2.3 + extern static function void set_default(uvm_table_printer printer) ; + + // Function: get_default + // Implementation of uvm_table_printer::get_default as defined in + // section 16.2.10.2.3 of 1800.2-2017. + // + // *Note:* + // The library implements get_default as described in IEEE 1800.2-2017 + // with the exception that this implementation will instance a + // uvm_table_printer if the most recent call to set_default() used an + // argument value of null. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 16.2.10.2.4 + extern static function uvm_table_printer get_default() ; + + // @uvm-ieee 1800.2-2017 auto 16.2.10.3 + extern virtual function void set_indent(int indent) ; + + // @uvm-ieee 1800.2-2017 auto 16.2.10.3 + extern virtual function int get_indent() ; + + extern virtual function void flush() ; + + // Variables- m_max_* + // + // holds max size of each column, so table columns can be resized dynamically + + protected int m_max_name=4; + protected int m_max_type=4; + protected int m_max_size=4; + protected int m_max_value=5; + + extern virtual function void pop_element(); + + +endclass + + +//------------------------------------------------------------------------------ +// +// Class: uvm_tree_printer +// +// By overriding various methods of the super class, +// the tree printer prints output in a tree format. +// +// The following shows sample output from the tree printer. +// +//| c1: (container@1013) { +//| d1: (mydata@1022) { +//| v1: 'hcb8f1c97 +//| e1: THREE +//| str: hi +//| } +//| value: 'h2d +//| } +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 16.2.11.1 +class uvm_tree_printer extends uvm_printer; + + protected string m_newline = "\n"; + protected string m_linefeed ; + + // @uvm-ieee 1800.2-2017 auto 16.2.11.2.2 + `uvm_object_utils(uvm_tree_printer) + // Variable -- NODOCS -- new + // + // Creates a new instance of ~uvm_tree_printer~. + + // @uvm-ieee 1800.2-2017 auto 16.2.11.2.1 + extern function new(string name=""); + + local static uvm_tree_printer m_default_tree_printer ; + + // @uvm-ieee 1800.2-2017 auto 16.2.11.2.3 + extern static function void set_default(uvm_tree_printer printer) ; + + // Function: get_default + // Implementation of uvm_tree_printer::get_default as defined in + // section 16.2.11.2.4 of 1800.2-2017. + // + // *Note:* + // The library implements get_default as described in IEEE 1800.2-2017 + // with the exception that this implementation will instance a + // uvm_tree_printer if the most recent call to set_default() used an + // argument value of null. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 16.2.11.2.4 + extern static function uvm_tree_printer get_default() ; + + // @uvm-ieee 1800.2-2017 auto 16.2.11.3.1 + extern virtual function void set_indent(int indent) ; + + // @uvm-ieee 1800.2-2017 auto 16.2.11.3.1 + extern virtual function int get_indent() ; + + // @uvm-ieee 1800.2-2017 auto 16.2.11.3.2 + extern virtual function void set_separators(string separators) ; + + // @uvm-ieee 1800.2-2017 auto 16.2.11.3.2 + extern virtual function string get_separators() ; + + extern virtual function void flush() ; + + // @uvm-ieee 1800.2-2017 auto 16.2.4.1 + extern virtual function string emit(); + + extern virtual function string m_emit_element(uvm_printer_element element, int unsigned level); + +endclass + + + +//------------------------------------------------------------------------------ +// +// Class: uvm_line_printer +// +// The line printer prints output in a line format. +// +// The following shows sample output from the line printer. +// +//| c1: (container@1013) { d1: (mydata@1022) { v1: 'hcb8f1c97 e1: THREE str: hi } value: 'h2d } +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 16.2.12.1 +class uvm_line_printer extends uvm_tree_printer; + + // @uvm-ieee 1800.2-2017 auto 16.2.12.2.2 + `uvm_object_utils(uvm_line_printer) + // Variable -- NODOCS -- new + // + // Creates a new instance of ~uvm_line_printer~. It differs from the + // only in that the output contains no line-feeds + // and indentation. + + // @uvm-ieee 1800.2-2017 auto 16.2.12.2.1 + // @uvm-ieee 1800.2-2017 auto 16.2.2.1 + extern function new(string name=""); + + local static uvm_line_printer m_default_line_printer ; + + // @uvm-ieee 1800.2-2017 auto 16.2.12.2.3 + // @uvm-ieee 1800.2-2017 auto 16.2.2.2 + extern static function void set_default(uvm_line_printer printer) ; + + // Function: get_default + // Implementation of uvm_line_printer::get_default as defined in + // section 16.2.12.2.3 of 1800.2-2017. + // + // *Note:* + // The library implements get_default as described in IEEE 1800.2-2017 + // with the exception that this implementation will instance a + // uvm_line_printer if the most recent call to set_default() used an + // argument value of null. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 16.2.2.3 + extern static function uvm_line_printer get_default() ; + + // @uvm-ieee 1800.2-2017 auto 16.2.12.3 + extern virtual function void set_separators(string separators) ; + + // @uvm-ieee 1800.2-2017 auto 16.2.12.3 + extern virtual function string get_separators() ; + + // @uvm-ieee 1800.2-2017 auto 16.2.4.2 + extern virtual function void flush() ; + +endclass + + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- m_uvm_printer_knobs +// +// The ~m_uvm_printer_knobs~ class defines the printer settings available to all +// printer subtypes. +// +//------------------------------------------------------------------------------ + +class m_uvm_printer_knobs; + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- header + // + // Indicates whether the function should be called when + // printing an object. + + bit header = 1; + + + // Variable -- NODOCS -- footer + // + // Indicates whether the function should be called when + // printing an object. + + bit footer = 1; + + + // Variable -- NODOCS -- full_name + // + // Indicates whether should print the full name of an identifier + // or just the leaf name. + + bit full_name = 0; +`endif + + // Variable -- NODOCS -- identifier + // + // Indicates whether should print the identifier. This is useful + // in cases where you just want the values of an object, but no identifiers. + + bit identifier = 1; + + + // Variable -- NODOCS -- type_name + // + // Controls whether to print a field's type name. + + bit type_name = 1; + + + // Variable -- NODOCS -- size + // + // Controls whether to print a field's size. + + bit size = 1; + + + // Variable -- NODOCS -- depth + // + // Indicates how deep to recurse when printing objects. + // A depth of -1 means to print everything. + + int depth = -1; + + + // Variable -- NODOCS -- reference + // + // Controls whether to print a unique reference ID for object handles. + // The behavior of this knob is simulator-dependent. + + bit reference = 1; + + + // Variable -- NODOCS -- begin_elements + // + // Defines the number of elements at the head of a list to print. + // Use -1 for no max. + + int begin_elements = 5; + + + // Variable -- NODOCS -- end_elements + // + // This defines the number of elements at the end of a list that + // should be printed. + + int end_elements = 5; + + + // Variable -- NODOCS -- prefix + // + // Specifies the string prepended to each output line + + string prefix = ""; + + + // Variable -- NODOCS -- indent + // + // This knob specifies the number of spaces to use for level indentation. + // The default level indentation is two spaces. + + int indent = 2; + + + // Variable -- NODOCS -- show_root + // + // This setting indicates whether or not the initial object that is printed + // (when current depth is 0) prints the full path name. By default, the first + // object is treated like all other objects and only the leaf name is printed. + + bit show_root = 0; + + + // Variable -- NODOCS -- mcd + // + // This is a file descriptor, or multi-channel descriptor, that specifies + // where the print output should be directed. + // + // By default, the output goes to the standard output of the simulator. + + int mcd = UVM_STDOUT; + + + // Variable -- NODOCS -- separator + // + // For tree printers only, determines the opening and closing + // separators used for nested objects. + + string separator = "{}"; + + + // Variable -- NODOCS -- show_radix + // + // Indicates whether the radix string ('h, and so on) should be prepended to + // an integral value when one is printed. + + bit show_radix = 1; + + + // Variable -- NODOCS -- default_radix + // + // This knob sets the default radix to use for integral values when no radix + // enum is explicitly supplied to the or + // methods. + + uvm_radix_enum default_radix = UVM_HEX; + + + // Variable -- NODOCS -- dec_radix + // + // This string should be prepended to the value of an integral type when a + // radix of is used for the radix of the integral object. + // + // When a negative number is printed, the radix is not printed since only + // signed decimal values can print as negative. + + string dec_radix = "'d"; + + + // Variable -- NODOCS -- bin_radix + // + // This string should be prepended to the value of an integral type when a + // radix of is used for the radix of the integral object. + + string bin_radix = "'b"; + + + // Variable -- NODOCS -- oct_radix + // + // This string should be prepended to the value of an integral type when a + // radix of is used for the radix of the integral object. + + string oct_radix = "'o"; + + + // Variable -- NODOCS -- unsigned_radix + // + // This is the string which should be prepended to the value of an integral + // type when a radix of is used for the radix of the integral + // object. + + string unsigned_radix = "'d"; + + + // Variable -- NODOCS -- hex_radix + // + // This string should be prepended to the value of an integral type when a + // radix of is used for the radix of the integral object. + + string hex_radix = "'h"; + + uvm_recursion_policy_enum recursion_policy ; + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- get_radix_str + // + // Converts the radix from an enumerated to a printable radix according to + // the radix printing knobs (bin_radix, and so on). + + function string get_radix_str(uvm_radix_enum radix); + if(show_radix == 0) + return ""; + if(radix == UVM_NORADIX) + radix = default_radix; + case(radix) + UVM_BIN: return bin_radix; + UVM_OCT: return oct_radix; + UVM_DEC: return dec_radix; + UVM_HEX: return hex_radix; + UVM_UNSIGNED: return unsigned_radix; + default: return ""; + endcase + endfunction + + // Deprecated knobs, hereafter ignored + int max_width = 999; + string truncation = "+"; + int name_width = -1; + int type_width = -1; + int size_width = -1; + int value_width = -1; + bit sprint = 1; +`endif +endclass + +`ifdef UVM_ENABLE_DEPRECATED_API +typedef m_uvm_printer_knobs uvm_table_printer_knobs; +typedef m_uvm_printer_knobs uvm_tree_printer_knobs; +typedef m_uvm_printer_knobs uvm_printer_knobs; +`endif // UVM_ENABLE_DEPRECATED_API + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ +function uvm_printer::new(string name=""); + super.new(name); + knobs = new ; + flush(); +endfunction + +function void uvm_printer::set_default(uvm_printer printer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_printer(printer) ; +endfunction + +function uvm_printer uvm_printer::get_default() ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_printer() ; +endfunction + +// print_field +// --------- + +function void uvm_printer::print_field (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + + string sz_str, val_str; + + if(type_name == "") begin + if(radix == UVM_TIME) + type_name ="time"; + else if(radix == UVM_STRING) + type_name ="string"; + else + type_name ="integral"; + end + + sz_str.itoa(size); + + if(radix == UVM_NORADIX) + radix = get_default_radix(); + + val_str = uvm_bitstream_to_string (value, size, radix, + get_radix_string(radix)); + +`ifdef UVM_ENABLE_DEPRECATED_API + name = adjust_name(name,scope_separator); +`else + name = uvm_leaf_scope(name,scope_separator); +`endif + + push_element(name,type_name,sz_str,val_str); + pop_element() ; + +endfunction + + +// print_field_int +// --------- + +function void uvm_printer::print_field_int (string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + + string sz_str, val_str; + + if(type_name == "") begin + if(radix == UVM_TIME) + type_name ="time"; + else if(radix == UVM_STRING) + type_name ="string"; + else + type_name ="integral"; + end + + sz_str.itoa(size); + + if(radix == UVM_NORADIX) + radix = get_default_radix(); + + val_str = uvm_integral_to_string (value, size, radix, + get_radix_string(radix)); + +`ifdef UVM_ENABLE_DEPRECATED_API + name = adjust_name(name,scope_separator); +`else + name = uvm_leaf_scope(name,scope_separator); +`endif + + push_element(name,type_name,sz_str,val_str); + pop_element() ; + +endfunction + + +// emit +// ---- + +function string uvm_printer::emit (); + `uvm_error("NO_OVERRIDE","emit() method not overridden in printer subtype") + return ""; +endfunction + +function void uvm_printer::flush (); + // recycle all elements that were on the stack + uvm_printer_element element = get_bottom_element() ; + uvm_printer_element all_descendent_elements[$] ; + + element = get_bottom_element() ; + if (element != null) begin + element.get_children(all_descendent_elements,1) ; //recursive + foreach (all_descendent_elements[i]) begin + m_recycled_elements.push_back(all_descendent_elements[i]) ; + all_descendent_elements[i].clear_children() ; + end + element.clear_children(); + m_recycled_elements.push_back(element) ; + // now delete the stack + m_element_stack.delete() ; + end + m_recur_states.delete(); + m_flushed = 1 ; +endfunction + +function void uvm_printer::set_name_enabled (bit enabled); + knobs.identifier = enabled ; +endfunction +function bit uvm_printer::get_name_enabled (); + return knobs.identifier ; +endfunction + +function void uvm_printer::set_type_name_enabled (bit enabled); + knobs.type_name = enabled ; +endfunction +function bit uvm_printer::get_type_name_enabled (); + return knobs.type_name ; +endfunction + +function void uvm_printer::set_size_enabled (bit enabled); + knobs.size = enabled ; +endfunction +function bit uvm_printer::get_size_enabled (); + return knobs.size ; +endfunction + +function void uvm_printer::set_id_enabled (bit enabled); + knobs.reference = enabled ; +endfunction +function bit uvm_printer::get_id_enabled (); + return knobs.reference ; +endfunction + +function void uvm_printer::set_radix_enabled (bit enabled); + knobs.show_radix = enabled ; +endfunction +function bit uvm_printer::get_radix_enabled (); + return knobs.show_radix ; +endfunction + +function void uvm_printer::set_radix_string (uvm_radix_enum radix, string prefix); + if (radix == UVM_DEC) knobs.dec_radix = prefix ; + else if (radix == UVM_BIN) knobs.bin_radix = prefix ; + else if (radix == UVM_OCT) knobs.oct_radix = prefix ; + else if (radix == UVM_UNSIGNED) knobs.unsigned_radix = prefix ; + else if (radix == UVM_HEX) knobs.hex_radix = prefix ; + else `uvm_warning("PRINTER_UNKNOWN_RADIX",$sformatf("set_radix_string called with unsupported radix %s",radix)) +endfunction +function string uvm_printer::get_radix_string (uvm_radix_enum radix); + if (radix == UVM_DEC) return knobs.dec_radix ; + else if (radix == UVM_BIN) return knobs.bin_radix ; + else if (radix == UVM_OCT) return knobs.oct_radix ; + else if (radix == UVM_UNSIGNED) return knobs.unsigned_radix ; + else if (radix == UVM_HEX) return knobs.hex_radix ; + else return ""; +endfunction + +function void uvm_printer::set_default_radix (uvm_radix_enum radix); + knobs.default_radix = radix ; +endfunction +function uvm_radix_enum uvm_printer::get_default_radix (); + return knobs.default_radix ; +endfunction + +function void uvm_printer::set_root_enabled (bit enabled); + knobs.show_root = enabled ; +endfunction +function bit uvm_printer::get_root_enabled (); + return knobs.show_root ; +endfunction + +function void uvm_printer::set_recursion_policy (uvm_recursion_policy_enum policy); + knobs.recursion_policy = policy ; +endfunction +function uvm_recursion_policy_enum uvm_printer::get_recursion_policy (); + return knobs.recursion_policy ; +endfunction + +function void uvm_printer::set_max_depth (int depth); + knobs.depth = depth ; +endfunction +function int uvm_printer::get_max_depth (); + return knobs.depth ; +endfunction + +function void uvm_printer::set_file (UVM_FILE fl); + knobs.mcd = fl ; +endfunction +function UVM_FILE uvm_printer::get_file (); + return knobs.mcd ; +endfunction + +function void uvm_printer::set_line_prefix (string prefix); + knobs.prefix = prefix ; +endfunction +function string uvm_printer::get_line_prefix (); + return knobs.prefix ; +endfunction + +function void uvm_printer::set_begin_elements (int elements = 5); + knobs.begin_elements = elements ; +endfunction +function int uvm_printer::get_begin_elements (); + return knobs.begin_elements ; +endfunction + +function void uvm_printer::set_end_elements (int elements = 5); + knobs.end_elements = elements ; +endfunction +function int uvm_printer::get_end_elements (); + return knobs.end_elements ; +endfunction + +function uvm_printer_element uvm_printer::get_bottom_element (); + if (m_element_stack.size() > 0) return m_element_stack[0] ; + else return null ; +endfunction + +function uvm_printer_element uvm_printer::get_top_element (); + if (m_element_stack.size() > 0) return m_element_stack[$] ; + else return null ; +endfunction + +function uvm_printer_element_proxy::new (string name=""); + super.new(name) ; +endfunction + +function void uvm_printer_element_proxy::get_immediate_children(uvm_printer_element s, + ref uvm_printer_element children[$]); + s.get_children(children,0) ; +endfunction + + + +function void uvm_printer::push_element ( string name, + string type_name, + string size, + string value=""); + uvm_printer_element element ; + uvm_printer_element parent ; + element = get_unused_element() ; + parent = get_top_element() ; + `ifdef UVM_ENABLE_DEPRECATED_API + if (knobs.full_name && (parent != null)) begin + name = $sformatf("%s.%s",parent.get_element_name(),name); + end + `endif + element.set(name,type_name,size,value); + if (parent != null) parent.add_child(element) ; + m_element_stack.push_back(element) ; +endfunction + +function void uvm_printer::pop_element (); + if (m_element_stack.size() > 1) begin + void'(m_element_stack.pop_back()); + end +endfunction + +function uvm_printer_element uvm_printer::get_unused_element() ; + uvm_printer_element element ; + if (m_recycled_elements.size() > 0) begin + element = m_recycled_elements.pop_back() ; + end + else begin + element = new() ; + end + return element ; +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + +// format_row +// ---------- + +function string uvm_printer::format_row (uvm_printer_row_info row); + return ""; +endfunction +`endif + +// print_array_header +// ------------------ + +function void uvm_printer::print_array_header (string name, + int size, + string arraytype="array", + byte scope_separator="."); + push_element(name,arraytype,$sformatf("%0d",size),"-"); + +endfunction + + +// print_array_footer +// ------------------ + +function void uvm_printer::print_array_footer (int size=0); + pop_element() ; +endfunction + + +// print_array_range +// ----------------- + +function void uvm_printer::print_array_range(int min, int max); + string tmpstr; + if(min == -1 && max == -1) + return; + if(min == -1) + min = max; + if(max == -1) + max = min; + if(max < min) + return; + print_generic_element("...", "...", "...", "..."); +endfunction + + +// print_object_header +// ------------------- + +function void uvm_printer::print_object_header (string name, + uvm_object value, + byte scope_separator="."); + if(name == "") + name = ""; + + push_element(name, + (value != null) ? value.get_type_name() : "object", + "-", + get_id_enabled() ? uvm_object_value_str(value) : "-"); +endfunction + + +// print_object +// ------------ + +function void uvm_printer::print_object (string name, uvm_object value, + byte scope_separator="."); + uvm_component comp, child_comp; + uvm_field_op field_op ; + uvm_recursion_policy_enum recursion_policy; + recursion_policy = get_recursion_policy(); + + if ((value == null) || + (recursion_policy == UVM_REFERENCE) || + (get_max_depth() == get_active_object_depth())) begin + print_object_header(name,value,scope_separator); // calls push_element + pop_element(); + end + else begin + push_active_object(value); + m_recur_states[value][recursion_policy] = uvm_policy::STARTED ; + print_object_header(name,value,scope_separator); // calls push_element + + // Handle children of the comp + // BOZO: Why isn't this handled inside of uvm_component::do_print? + if($cast(comp, value)) begin + string name; + if (comp.get_first_child(name)) + do begin + child_comp = comp.get_child(name); + if(child_comp.print_enabled) + this.print_object(name,child_comp); + end while (comp.get_next_child(name)); + end + + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_PRINT,this,null); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) + value.do_print(this); + field_op.m_recycle(); + + pop_element() ; // matches push in print_object_header + + m_recur_states[value][recursion_policy] = uvm_policy::FINISHED ; + void'(pop_active_object()); + end +endfunction + + +// istop +// ----- + +function bit uvm_printer::istop (); + return (get_active_object_depth() == 0); +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + +// adjust_name +// ----------- + +function string uvm_printer::adjust_name(string id, byte scope_separator="."); + if (get_root_enabled() && + istop() || + knobs.full_name || + id == "...") + return id; + return uvm_leaf_scope(id, scope_separator); +endfunction + +`endif + +// print_generic +// ------------- + +function void uvm_printer::print_generic (string name, + string type_name, + int size, + string value, + byte scope_separator="."); + + push_element(name, + type_name, + (size == -2 ? "..." : $sformatf("%0d",size)), + value); + pop_element(); + +endfunction + + +function void uvm_printer::print_generic_element (string name, + string type_name, + string size, + string value); + push_element(name,type_name,size,value); + pop_element() ; +endfunction + + +// print_time +// ---------- + +function void uvm_printer::print_time (string name, + time value, + byte scope_separator="."); + print_field_int(name, value, 64, UVM_TIME, scope_separator); +endfunction + + +// print_string +// ------------ + +function void uvm_printer::print_string (string name, + string value, + byte scope_separator="."); + + push_element(name, + "string", + $sformatf("%0d",value.len()), + (value == "" ? "\"\"" : value)); + pop_element() ; + +endfunction + +function uvm_policy::recursion_state_e uvm_printer::object_printed (uvm_object value, + uvm_recursion_policy_enum recursion); + + if (!m_recur_states.exists(value)) return NEVER ; + if (!m_recur_states[value].exists(recursion)) return NEVER ; + else return m_recur_states[value][recursion] ; +endfunction + +// print_real +// ---------- + +function void uvm_printer::print_real (string name, + real value, + byte scope_separator="."); + + push_element(name,"real","64",$sformatf("%f",value)); + pop_element() ; + +endfunction + + +// index_string +// ------------ + +function string uvm_printer::index_string(int index, string name=""); + index_string.itoa(index); + index_string = { name, "[", index_string, "]" }; +endfunction + +//------------------------------------------------------------------------------ +// Class- uvm_printer_element +//------------------------------------------------------------------------------ + +function uvm_printer_element::new (string name = ""); + super.new(name) ; +endfunction + +function void uvm_printer_element::set (string element_name = "", + string element_type_name = "", + string element_size = "", + string element_value = "" + ); + m_name = element_name ; + m_type_name = element_type_name ; + m_size = element_size ; + m_value = element_value ; +endfunction + +function void uvm_printer_element::set_element_name (string element_name); + m_name = element_name ; +endfunction +function string uvm_printer_element::get_element_name (); + return m_name ; +endfunction + +function void uvm_printer_element::set_element_type_name (string element_type_name); + m_type_name = element_type_name ; +endfunction +function string uvm_printer_element::get_element_type_name (); + return m_type_name ; +endfunction + +function void uvm_printer_element::set_element_size (string element_size); + m_size = element_size ; +endfunction +function string uvm_printer_element::get_element_size (); + return m_size ; +endfunction + +function void uvm_printer_element::set_element_value (string element_value); + m_value = element_value ; +endfunction +function string uvm_printer_element::get_element_value (); + return m_value ; +endfunction + +function void uvm_printer_element::add_child(uvm_printer_element child) ; + m_children.push_back(child) ; +endfunction +function void uvm_printer_element::get_children(ref uvm_printer_element children[$], input bit recurse) ; + foreach (m_children[i]) begin + children.push_back(m_children[i]) ; + if (recurse) begin + m_children[i].get_children(children,1) ; + end + end +endfunction +function void uvm_printer_element::clear_children() ; + m_children.delete() ; +endfunction + +//------------------------------------------------------------------------------ +// Class- uvm_table_printer +//------------------------------------------------------------------------------ + +// new +// --- + +function uvm_table_printer::new(string name=""); + super.new(name); +endfunction + + +function void uvm_table_printer::pop_element(); + int name_len; + int level ; + uvm_printer_element popped ; + string name_str ; + string type_name_str ; + string size_str ; + string value_str ; + + popped = get_top_element() ; + + level = m_get_stack_size() - 1 ; + name_str = popped.get_element_name() ; + type_name_str = popped.get_element_type_name() ; + size_str = popped.get_element_size() ; + value_str = popped.get_element_value() ; + + if ((name_str.len() + (get_indent() * level)) > m_max_name) m_max_name = (name_str.len() + (get_indent() * level)); + if (type_name_str.len() > m_max_type) m_max_type = type_name_str.len(); + if (size_str.len() > m_max_size) m_max_size = size_str.len(); + if (value_str.len() > m_max_value) m_max_value = value_str.len(); + + super.pop_element() ; + +endfunction + +// emit +// ---- + +function string uvm_table_printer::emit(); + + string s; + string user_format; + static string dash; // = "---------------------------------------------------------------------------------------------------"; + string dashes; + + string linefeed; + + if (!m_flushed) begin + `uvm_error("UVM/PRINT/NO_FLUSH","printer emit() method called twice without intervening uvm_printer::flush()") + end + else m_flushed = 0 ; + linefeed = {"\n", get_line_prefix()}; + + begin + int q[5]; + int m; + int qq[$]; + + q = '{m_max_name,m_max_type,m_max_size,m_max_value,100}; + qq = q.max; + m = qq[0]; + if(dash.len() 0) && (value_str[0] == "@")) // is an object w/ id_enabled() on + result = {result,"(",element.get_element_type_name(),value_str,") "}; + else + if (get_type_name_enabled() && + (element.get_element_type_name() != "" || + element.get_element_type_name() != "-" || + element.get_element_type_name() != "...")) + result = {result,"(",element.get_element_type_name(),") "}; + + // Size + if (get_size_enabled()) begin + if (element.get_element_size() != "" || element.get_element_size() != "-") + result = {result,"(",element.get_element_size(),") "}; + end + + if (element_children.size() > 0) begin + result = {result, string'(separators[0]), m_linefeed}; + end + else result = {result, value_str, " ", m_linefeed}; + + //process all children (if any) of this element + foreach (element_children[i]) begin + result = {result, m_emit_element(element_children[i],level+1)} ; + end + //if there were children, add the closing separator + if (element_children.size() > 0) begin + result = {result, indent_str, string'(separators[1]), m_linefeed}; + end + end + return result ; +endfunction : m_emit_element + +function void uvm_table_printer::set_default(uvm_table_printer printer) ; +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_default_table_printer = printer ; +`else + m_default_table_printer = printer ; +`endif +endfunction + +function uvm_table_printer uvm_table_printer::get_default() ; +`ifdef UVM_ENABLE_DEPRECATED_API + if (uvm_default_table_printer == null) begin + uvm_default_table_printer = new() ; + end + return uvm_default_table_printer ; +`else + if (m_default_table_printer == null) begin + m_default_table_printer = new("uvm_default_table_printer") ; + end + return m_default_table_printer ; +`endif +endfunction + +function void uvm_table_printer::set_indent(int indent) ; + m_uvm_printer_knobs _knobs = get_knobs(); + _knobs.indent = indent ; +endfunction +function int uvm_table_printer::get_indent() ; + m_uvm_printer_knobs _knobs = get_knobs(); + return _knobs.indent ; +endfunction + +function void uvm_table_printer::flush() ; + super.flush() ; + m_max_name=4; + m_max_type=4; + m_max_size=4; + m_max_value=5; + //set_indent(2) ; // LRM says to include this call +endfunction + + +function void uvm_tree_printer::set_default(uvm_tree_printer printer) ; +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_default_tree_printer = printer ; +`else + m_default_tree_printer = printer ; +`endif +endfunction + +function uvm_tree_printer uvm_tree_printer::get_default() ; +`ifdef UVM_ENABLE_DEPRECATED_API + if (uvm_default_tree_printer == null) begin + uvm_default_tree_printer = new() ; + end + return uvm_default_tree_printer ; +`else + if (m_default_tree_printer == null) begin + m_default_tree_printer = new("uvm_default_tree_printer") ; + end + return m_default_tree_printer ; +`endif +endfunction + +function uvm_line_printer::new(string name="") ; + super.new(name); + m_newline = " "; + set_indent(0); +endfunction + +function void uvm_line_printer::set_default(uvm_line_printer printer) ; +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_default_line_printer = printer ; +`else + m_default_line_printer = printer ; +`endif +endfunction + +function uvm_line_printer uvm_line_printer::get_default() ; +`ifdef UVM_ENABLE_DEPRECATED_API + if (uvm_default_line_printer == null) begin + uvm_default_line_printer = new() ; + end + return uvm_default_line_printer ; +`else + if (m_default_line_printer == null) begin + m_default_line_printer = new("uvm_default_line_printer") ; + end + return m_default_line_printer ; +`endif +endfunction + +function void uvm_line_printer::set_separators(string separators) ; + m_uvm_printer_knobs _knobs = get_knobs(); + if (separators.len() < 2) begin + `uvm_error("UVM/PRINT/SHORT_SEP",$sformatf("Bad call: set_separators(%s) (Argument must have at least 2 characters)",separators)) + end + _knobs.separator = separators ; +endfunction +function string uvm_line_printer::get_separators() ; + m_uvm_printer_knobs _knobs = get_knobs(); + return _knobs.separator ; +endfunction + +function void uvm_line_printer::flush() ; + super.flush() ; + //set_indent(0); // LRM says to include this call + //set_separators("{}"); // LRM says to include this call +endfunction + diff --git a/test_regress/t/t_uvm/base/uvm_queue.svh b/test_regress/t/t_uvm/base/uvm_queue.svh index f88af82dc3..e9dbcda812 100644 --- a/test_regress/t/t_uvm/base/uvm_queue.svh +++ b/test_regress/t/t_uvm/base/uvm_queue.svh @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 // //------------------------------------------------------------------------------ // Copyright 2007-2011 Mentor Graphics Corporation @@ -37,29 +36,17 @@ // demand, and passed and stored by reference. //------------------------------------------------------------------------------ -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- - -//UVM ~ // @uvm-ieee 1800.2-2017 auto 11.3.1 class uvm_queue #(type T=int) extends uvm_object; typedef uvm_queue #(T) this_type; -//UVM `uvm_object_param_utils(uvm_queue#(T)) -//UVM `uvm_type_name_decl("uvm_queue") + `uvm_object_param_utils(uvm_queue#(T)) + `uvm_type_name_decl("uvm_queue") static local this_type m_global_queue; protected T queue[$]; -//UVM - static function void uvmt_drop_globals(); - m_global_queue = null; - endfunction -//UVM - // Function -- NODOCS -- new // // Creates a new queue with the given ~name~. @@ -72,7 +59,7 @@ class uvm_queue #(type T=int) extends uvm_object; // Function -- NODOCS -- get_global_queue // - // Returns the singleton global queue for the item type, T. + // Returns the singleton global queue for the item type, T. // // This allows items to be shared amongst components throughout the // verification environment. @@ -86,12 +73,12 @@ class uvm_queue #(type T=int) extends uvm_object; // Function -- NODOCS -- get_global // - // Returns the specified item instance from the global item queue. + // Returns the specified item instance from the global item queue. // @uvm-ieee 1800.2-2017 auto 11.3.2.3 static function T get_global (int index); this_type gqueue; - gqueue = get_global_queue(); + gqueue = get_global_queue(); return gqueue.get(index); endfunction @@ -113,7 +100,7 @@ class uvm_queue #(type T=int) extends uvm_object; end return queue[index]; endfunction - + // Function -- NODOCS -- size // @@ -209,14 +196,14 @@ class uvm_queue #(type T=int) extends uvm_object; wait(queue.size() > 0); endtask -//UVM virtual function void do_copy (uvm_object rhs); -//UVM this_type p; -//UVM super.do_copy(rhs); -//UVM if (rhs == null || !$cast(p, rhs)) -//UVM return; -//UVM queue = p.queue; -//UVM endfunction - + virtual function void do_copy (uvm_object rhs); + this_type p; + super.do_copy(rhs); + if (rhs == null || !$cast(p, rhs)) + return; + queue = p.queue; + endfunction + virtual function string convert2string(); return $sformatf("%p",queue); endfunction diff --git a/test_regress/t/t_uvm/base/uvm_recorder.svh b/test_regress/t/t_uvm/base/uvm_recorder.svh new file mode 100644 index 0000000000..203016027b --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_recorder.svh @@ -0,0 +1,1066 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2011-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, 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. +//----------------------------------------------------------------------------- + +typedef class uvm_report_message; + +// File -- NODOCS -- UVM Recorders +// +// The uvm_recorder class serves two purposes: +// - Firstly, it is an abstract representation of a record within a +// . +// - Secondly, it is a policy object for recording fields ~into~ that +// record within the ~stream~. +// + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_recorder +// +// Abstract class which defines the ~recorder~ API. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 16.4.1 +virtual class uvm_recorder extends uvm_policy; + + `uvm_object_abstract_utils(uvm_recorder) + + // Variable- m_stream_dap + // Data access protected reference to the stream + local uvm_set_before_get_dap#(uvm_tr_stream) m_stream_dap; + + // Variable- m_warn_null_stream + // Used to limit the number of warnings + local bit m_warn_null_stream; + + // Variable- m_is_opened + // Used to indicate recorder is open + local bit m_is_opened; + + // Variable- m_is_closed + // Used to indicate recorder is closed + local bit m_is_closed; + + // !m_is_opened && !m_is_closed == m_is_freed + + // Variable- m_open_time + // Used to store the open_time + local time m_open_time; + + // Variable- m_close_time + // Used to store the close_time + local time m_close_time; + + // Variable- recording_depth + int recording_depth; + + // Variable -- NODOCS -- default_radix + // + // This is the default radix setting if is called without + // a radix. + + uvm_radix_enum default_radix = UVM_HEX; + +`ifdef UVM_ENABLE_DEPRECATED_API + + // Variable -- NODOCS -- physical + // + // This bit provides a filtering mechanism for fields. + // + // The and physical settings allow an object to distinguish between + // two different classes of fields. + // + // It is up to you, in the method, to test the + // setting of this field if you want to use the physical trait as a filter. + + bit physical = 1; + + + // Variable -- NODOCS -- abstract + // + // This bit provides a filtering mechanism for fields. + // + // The abstract and physical settings allow an object to distinguish between + // two different classes of fields. + // + // It is up to you, in the method, to test the + // setting of this field if you want to use the abstract trait as a filter. + + bit abstract = 1; + +`endif // `ifdef UVM_ENABLE_DEPRECATED_API + + // Variable -- NODOCS -- identifier + // + // This bit is used to specify whether or not an object's reference should be + // recorded when the object is recorded. + + bit identifier = 1; + + + // Variable -- NODOCS -- recursion_policy + // + // Sets the recursion policy for recording objects. + // + // The default policy is deep (which means to recurse an object). + +`ifndef UVM_ENABLE_DEPRECATED_API + local +`endif + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + + // @uvm-ieee 1800.2-2017 auto 16.4.2.1 + virtual function void set_recursion_policy(uvm_recursion_policy_enum policy); + this.policy = policy; + endfunction : set_recursion_policy + + // @uvm-ieee 1800.2-2017 auto 16.4.2.1 + virtual function uvm_recursion_policy_enum get_recursion_policy(); + return this.policy; + endfunction : get_recursion_policy + + // @uvm-ieee 1800.2-2017 auto 16.4.4.1 + virtual function void flush(); + policy = UVM_DEFAULT_POLICY; + identifier = 1; + free(); + endfunction : flush + + // Variable- m_ids_by_recorder + // An associative array of int, indexed by uvm_recorders. This + // provides a unique 'id' or 'handle' for each recorder, which can be + // used to identify the recorder. + // + // By default, neither ~m_ids_by_recorder~ or ~m_recorders_by_id~ are + // used. Recorders are only placed in the arrays when the user + // attempts to determine the id for a recorder. + local static int m_ids_by_recorder[uvm_recorder]; + + + function new(string name = "uvm_recorder"); + super.new(name); + m_stream_dap = new("stream_dap"); + m_warn_null_stream = 1; + endfunction + + // Group -- NODOCS -- Configuration API + + + // @uvm-ieee 1800.2-2017 auto 16.4.3 + function uvm_tr_stream get_stream(); + if (!m_stream_dap.try_get(get_stream)) begin + if (m_warn_null_stream == 1) + `uvm_warning("UVM/REC/NO_CFG", + $sformatf("attempt to retrieve STREAM from '%s' before it was set!", + get_name())) + m_warn_null_stream = 0; + end + endfunction : get_stream + + // Group -- NODOCS -- Transaction Recorder API + // + // Once a recorder has been opened via , the user + // can ~close~ the recorder. + // + // Due to the fact that many database implementations will require crossing + // a language boundary, an additional step of ~freeing~ the recorder is required. + // + // A ~link~ can be established within the database any time between ~open~ and + // ~free~, however it is illegal to establish a link after ~freeing~ the recorder. + // + + + // @uvm-ieee 1800.2-2017 auto 16.4.4.2 + function void close(time close_time = 0); + if (close_time == 0) + close_time = $realtime; + + if (!is_open()) + return; + + do_close(close_time); + + m_is_opened = 0; + m_is_closed = 1; + m_close_time = close_time; + endfunction : close + + + // @uvm-ieee 1800.2-2017 auto 16.4.4.3 + function void free(time close_time = 0); + process p=process::self(); + string s; + + uvm_tr_stream stream; + + if (!is_open() && !is_closed()) + return; + + if (is_open()) begin + close(close_time); + end + + do_free(); + + // Clear out internal state + stream = get_stream(); + + m_is_closed = 0; + if(p != null) + s=p.get_randstate(); + m_stream_dap = new("stream_dap"); + if(p != null) + p.set_randstate(s); + m_warn_null_stream = 1; + if (m_ids_by_recorder.exists(this)) + m_free_id(m_ids_by_recorder[this]); + + // Clear out stream state + if (stream != null) + stream.m_free_recorder(this); + endfunction : free + + + // @uvm-ieee 1800.2-2017 auto 16.4.4.4 + function bit is_open(); + return m_is_opened; + endfunction : is_open + + + // @uvm-ieee 1800.2-2017 auto 16.4.4.5 + function time get_open_time(); + return m_open_time; + endfunction : get_open_time + + + // @uvm-ieee 1800.2-2017 auto 16.4.4.6 + function bit is_closed(); + return m_is_closed; + endfunction : is_closed + + + // @uvm-ieee 1800.2-2017 auto 16.4.4.7 + function time get_close_time(); + return m_close_time; + endfunction : get_close_time + + // Function- m_do_open + // Initializes the internal state of the recorder. + // + // Parameters -- NODOCS -- + // stream - The stream which spawned this recorder + // + // This method will trigger a call. + // + // An error will be asserted if: + // - ~m_do_open~ is called more than once without the + // recorder being ~freed~ in between. + // - ~stream~ is ~null~ + function void m_do_open(uvm_tr_stream stream, time open_time, string type_name); + uvm_tr_stream m_stream; + if (stream == null) begin + `uvm_error("UVM/REC/NULL_STREAM", + $sformatf("Illegal attempt to set STREAM for '%s' to ''", + this.get_name())) + return; + end + + if (m_stream_dap.try_get(m_stream)) begin + `uvm_error("UVM/REC/RE_INIT", + $sformatf("Illegal attempt to re-initialize '%s'", + this.get_name())) + return; + end + + m_stream_dap.set(stream); + m_open_time = open_time; + m_is_opened = 1; + + do_open(stream, open_time, type_name); + endfunction : m_do_open + + // Group -- NODOCS -- Handles + + + // Variable- m_recorders_by_id + // A corollary to ~m_ids_by_recorder~, this indexes the recorders by their + // unique ids. + local static uvm_recorder m_recorders_by_id[int]; + + // Variable- m_id + // Static int marking the last assigned id. + local static int m_id; + + // Function- m_free_id + // Frees the id/recorder link (memory cleanup) + // + static function void m_free_id(int id); + uvm_recorder recorder; + if ((!$isunknown(id)) && (m_recorders_by_id.exists(id))) + recorder = m_recorders_by_id[id]; + + if (recorder != null) begin + m_recorders_by_id.delete(id); + m_ids_by_recorder.delete(recorder); + end + endfunction : m_free_id + + + // @uvm-ieee 1800.2-2017 auto 16.4.5.1 + function int get_handle(); + if (!is_open() && !is_closed()) begin + return 0; + end + else begin + int handle = get_inst_id(); + + // Check for the weird case where our handle changed. + if (m_ids_by_recorder.exists(this) && m_ids_by_recorder[this] != handle) + m_recorders_by_id.delete(m_ids_by_recorder[this]); + + m_recorders_by_id[handle] = this; + m_ids_by_recorder[this] = handle; + + return handle; + end + endfunction : get_handle + + + // @uvm-ieee 1800.2-2017 auto 16.4.5.2 + static function uvm_recorder get_recorder_from_handle(int id); + if (id == 0) + return null; + + if (($isunknown(id)) || (!m_recorders_by_id.exists(id))) + return null; + + return m_recorders_by_id[id]; + endfunction : get_recorder_from_handle + + // Group -- NODOCS -- Attribute Recording + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.1 + function void record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX); + if (get_stream() == null) begin + return; + end + do_record_field(name, value, size, radix); + endfunction : record_field + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.2 + function void record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX); + if (get_stream() == null) begin + return; + end + do_record_field_int(name, value, size, radix); + endfunction : record_field_int + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.3 + function void record_field_real(string name, + real value); + if (get_stream() == null) begin + return; + end + do_record_field_real(name, value); + endfunction : record_field_real + + // @uvm-ieee 1800.2-2017 auto 16.4.6.4 + function void record_object(string name, + uvm_object value); + if (get_stream() == null) begin + return; + end + + if (value == null) + do_record_object(name, value); + else begin + push_active_object(value); + do_record_object(name, value); + void'(pop_active_object()); + end + endfunction : record_object + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.5 + function void record_string(string name, + string value); + if (get_stream() == null) begin + return; + end + + do_record_string(name, value); + endfunction : record_string + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.6 + function void record_time(string name, + time value); + if (get_stream() == null) begin + return; + end + + do_record_time(name, value); + endfunction : record_time + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.7 + function void record_generic(string name, + string value, + string type_name=""); + if (get_stream() == null) begin + return; + end + + do_record_generic(name, value, type_name); + endfunction : record_generic + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.8 + virtual function bit use_record_attribute(); + return 0; + endfunction : use_record_attribute + + + // @uvm-ieee 1800.2-2017 auto 16.4.6.9 + virtual function int get_record_attribute_handle(); + return get_handle(); + endfunction : get_record_attribute_handle + + // Group -- NODOCS -- Implementation Agnostic API + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.1 + protected virtual function void do_open(uvm_tr_stream stream, + time open_time, + string type_name); + endfunction : do_open + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.2 + protected virtual function void do_close(time close_time); + endfunction : do_close + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.3 + protected virtual function void do_free(); + endfunction : do_free + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.4 + pure virtual protected function void do_record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.5 + pure virtual protected function void do_record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix); + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.6 + pure virtual protected function void do_record_field_real(string name, + real value); + + + // Function : do_record_object + // The library implements do_record_object as virtual even though the LRM + // calls for pure virtual. Mantis 6591 calls for the LRM to move to + // virtual. The implemented signature is: + // virtual protected function void do_record_object(string name, uvm_object value); + + // @uvm-ieee 1800.2-2017 auto 16.4.7.7 + virtual protected function void do_record_object(string name, + uvm_object value); + if ((get_recursion_policy() != UVM_REFERENCE) && + (value != null)) begin + uvm_field_op field_op = uvm_field_op::m_get_available_op(); + field_op.set(UVM_RECORD, this, null); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) + value.do_record(this); + field_op.m_recycle(); + end + endfunction : do_record_object + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.9 + pure virtual protected function void do_record_string(string name, + string value); + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.10 + pure virtual protected function void do_record_time(string name, + time value); + + + // @uvm-ieee 1800.2-2017 auto 16.4.7.11 + pure virtual protected function void do_record_generic(string name, + string value, + string type_name); + + + // The following code is primarily for backwards compat. purposes. "Transaction + // Handles" are useful when connecting to a backend, but when passing the information + // back and forth within simulation, it is safer to user the ~recorder~ itself + // as a reference to the transaction within the database. + + //------------------------------ + // Group- Vendor-Independent API + //------------------------------ + + + // UVM provides only a text-based default implementation. + // Vendors provide subtype implementations and overwrite the + // handle. + + + // Function- open_file + // + // Opens the file in the property and assigns to the + // file descriptor . + // + virtual function bit open_file(); + return 0; + endfunction + + // Function- create_stream + // + // + virtual function int create_stream (string name, + string t, + string scope); + return -1; + endfunction + + + // Function- m_set_attribute + // + // + virtual function void m_set_attribute (int txh, + string nm, + string value); + endfunction + + + // Function- set_attribute + // + virtual function void set_attribute (int txh, + string nm, + logic [1023:0] value, + uvm_radix_enum radix, + int numbits=1024); + endfunction + + + // Function- check_handle_kind + // + // + virtual function int check_handle_kind (string htype, int handle); + return 0; + endfunction + + + // Function- begin_tr + // + // + virtual function int begin_tr(string txtype, + int stream, + string nm, + string label="", + string desc="", + time begin_time=0); + return -1; + endfunction + + + // Function- end_tr + // + // + virtual function void end_tr (int handle, time end_time=0); + endfunction + + + // Function- link_tr + // + // + virtual function void link_tr(int h1, + int h2, + string relation=""); + endfunction + + + + // Function- free_tr + // + // + virtual function void free_tr(int handle); + endfunction + +endclass // uvm_recorder + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_text_recorder +// +// The ~uvm_text_recorder~ is the default recorder implementation for the +// . +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + +class uvm_text_recorder extends uvm_recorder; + + `uvm_object_utils(uvm_text_recorder) + + // Variable- m_text_db + // + // Reference to the text database backend + uvm_text_tr_database m_text_db; + + // Function --NODOCS-- new + // Constructor + // + // Parameters --NODOCS-- + // name - Instance name + function new(string name="unnamed-uvm_text_recorder"); + super.new(name); + endfunction : new + + // Group --NODOCS-- Implementation Agnostic API + + // Function --NODOCS-- do_open + // Callback triggered via . + // + // Text-backend specific implementation. + protected virtual function void do_open(uvm_tr_stream stream, + time open_time, + string type_name); + $cast(m_text_db, stream.get_db()); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " OPEN_RECORDER @%0t {TXH:%0d STREAM:%0d NAME:%s TIME:%0t TYPE=\"%0s\"}", + $realtime, + this.get_handle(), + stream.get_handle(), + this.get_name(), + open_time, + type_name); + endfunction : do_open + + // Function --NODOCS-- do_close + // Callback triggered via . + // + // Text-backend specific implementation. + protected virtual function void do_close(time close_time); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " CLOSE_RECORDER @%0t {TXH:%0d TIME=%0t}", + $realtime, + this.get_handle(), + close_time); + + end + endfunction : do_close + + // Function --NODOCS-- do_free + // Callback triggered via . + // + // Text-backend specific implementation. + protected virtual function void do_free(); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " FREE_RECORDER @%0t {TXH:%0d}", + $realtime, + this.get_handle()); + end + m_text_db = null; + endfunction : do_free + + // Function --NODOCS-- do_record_field + // Records an integral field (less than or equal to 4096 bits). + // + // Text-backend specific implementation. + protected virtual function void do_record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + if (!radix) + radix = default_radix; + + write_attribute(m_current_context(name), + value, + radix, + size); + + endfunction : do_record_field + + + // Function --NODOCS-- do_record_field_int + // Records an integral field (less than or equal to 64 bits). + // + // Text-backend specific implementation. + protected virtual function void do_record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix); + if (!radix) + radix = default_radix; + + write_attribute_int(m_current_context(name), + value, + radix, + size); + + endfunction : do_record_field_int + + + // Function --NODOCS-- do_record_field_real + // Record a real field. + // + // Text-backened specific implementation. + protected virtual function void do_record_field_real(string name, + real value); + bit [63:0] ival = $realtobits(value); + + write_attribute_int(m_current_context(name), + ival, + UVM_REAL, + 64); + endfunction : do_record_field_real + + // Stores the passed-in names of the objects in the hierarchy + local string m_object_names[$]; + local function string m_current_context(string name=""); + if (m_object_names.size() == 0) + return name; //?? + else if ((m_object_names.size() == 1) && (name=="")) + return m_object_names[0]; + else begin + string full_name; + foreach(m_object_names[i]) begin + if (i == m_object_names.size() - 1) + full_name = {full_name, m_object_names[i]}; + else + full_name = {full_name, m_object_names[i], "."}; + end + if (name != "") + return {full_name, ".", name}; + else + return full_name; + end + endfunction : m_current_context + + + // Function --NODOCS-- do_record_object + // Record an object field. + // + // Text-backend specific implementation. + // + // The method uses ~identifier~ to determine whether or not to + // record the object instance id, and ~recursion_policy~ to + // determine whether or not to recurse into the object. + protected virtual function void do_record_object(string name, + uvm_object value); + int v; + string str; + + if(identifier) begin + if(value != null) begin + v = value.get_inst_id(); + end + write_attribute_int("inst_id", + v, + UVM_DEC, + 32); + end + + if (get_active_object_depth() > 1) + m_object_names.push_back(name); + super.do_record_object(name, value); + if (get_active_object_depth() > 1) + void'(m_object_names.pop_back()); + endfunction : do_record_object + + // Function --NODOCS-- do_record_string + // Records a string field. + // + // Text-backend specific implementation. + protected virtual function void do_record_string(string name, + string value); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + m_current_context(name), + value, + "UVM_STRING", + 8+value.len()); + end + endfunction : do_record_string + + // Function --NODOCS-- do_record_time + // Records a time field. + // + // Text-backend specific implementation. + protected virtual function void do_record_time(string name, + time value); + write_attribute_int(m_current_context(name), + value, + UVM_TIME, + 64); + endfunction : do_record_time + + // Function --NODOCS-- do_record_generic + // Records a name/value pair, where ~value~ has been converted to a string. + // + // Text-backend specific implementation. + protected virtual function void do_record_generic(string name, + string value, + string type_name); + write_attribute(m_current_context(name), + uvm_string_to_bits(value), + UVM_STRING, + 8+value.len()); + endfunction : do_record_generic + + // Group: Implementation Specific API + + // Function: write_attribute + // Outputs a attribute to the textual log. + // + // Parameters: + // nm - Name of the attribute + // value - Value + // radix - Radix of the output + // numbits - number of valid bits + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + function void write_attribute(string nm, + uvm_bitstream_t value, + uvm_radix_enum radix, + int numbits=$bits(uvm_bitstream_t)); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + nm, + uvm_bitstream_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction : write_attribute + + // Function: write_attribute_int + // Outputs an attribute to the textual log + // + // Parameters: + // nm - Name of the attribute + // value - Value + // radix - Radix of the output + // numbits - number of valid bits + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + function void write_attribute_int(string nm, + uvm_integral_t value, + uvm_radix_enum radix, + int numbits=$bits(uvm_bitstream_t)); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + nm, + uvm_integral_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction : write_attribute_int + + /// LEFT FOR BACKWARDS COMPAT ONLY!!!!!!!! + + //------------------------------ + // Group- Vendor-Independent API + //------------------------------ + + + // UVM provides only a text-based default implementation. + // Vendors provide subtype implementations and overwrite the + // handle. + + string filename; + bit filename_set; + + // Function- open_file + // + // Opens the file in the property and assigns to the + // file descriptor . + // + virtual function bit open_file(); + if (!filename_set) begin + m_text_db.set_file_name(filename); + end + return m_text_db.open_db(); + endfunction + + + // Function- create_stream + // + // + virtual function int create_stream (string name, + string t, + string scope); + uvm_text_tr_stream stream; + if (open_file()) begin + $cast(stream,m_text_db.open_stream(name, scope, t)); + return stream.get_handle(); + end + return 0; + endfunction + + + // Function- m_set_attribute + // + // + virtual function void m_set_attribute (int txh, + string nm, + string value); + if (open_file()) begin + UVM_FILE file = m_text_db.m_file; + $fdisplay(file," SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s}", $realtime,txh,nm,value); + end + endfunction + + + // Function- set_attribute + // + // + virtual function void set_attribute (int txh, + string nm, + logic [1023:0] value, + uvm_radix_enum radix, + int numbits=1024); + if (open_file()) begin + UVM_FILE file = m_text_db.m_file; + $fdisplay(file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + txh, + nm, + uvm_bitstream_to_string(value, numbits, radix), + radix.name(), + numbits); + + end + endfunction + + + // Function- check_handle_kind + // + // + virtual function int check_handle_kind (string htype, int handle); + return ((uvm_recorder::get_recorder_from_handle(handle) != null) || + (uvm_tr_stream::get_stream_from_handle(handle) != null)); + endfunction + + + // Function- begin_tr + // + // + virtual function int begin_tr(string txtype, + int stream, + string nm, + string label="", + string desc="", + time begin_time=0); + if (open_file()) begin + uvm_tr_stream stream_obj = uvm_tr_stream::get_stream_from_handle(stream); + uvm_recorder recorder; + + if (stream_obj == null) + return -1; + + recorder = stream_obj.open_recorder(nm, begin_time, txtype); + + return recorder.get_handle(); + end + return -1; + endfunction + + + // Function- end_tr + // + // + virtual function void end_tr (int handle, time end_time=0); + if (open_file()) begin + uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle); + if (record != null) begin + record.close(end_time); + end + end + endfunction + + + // Function- link_tr + // + // + virtual function void link_tr(int h1, + int h2, + string relation=""); + if (open_file()) + $fdisplay(m_text_db.m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", $realtime,h1,h2,relation); + endfunction + + + + // Function- free_tr + // + // + virtual function void free_tr(int handle); + if (open_file()) begin + uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle); + if (record != null) begin + record.free(); + end + end + endfunction // free_tr + +endclass : uvm_text_recorder + + + diff --git a/test_regress/t/t_uvm/base/uvm_registry.svh b/test_regress/t/t_uvm/base/uvm_registry.svh new file mode 100644 index 0000000000..ad9397f3bb --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_registry.svh @@ -0,0 +1,740 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2018 Qualcomm, Inc. +// Copyright 2014 Intel Corporation +// Copyright 2011-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2018 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +`ifndef UVM_REGISTRY_SVH +`define UVM_REGISTRY_SVH + +//------------------------------------------------------------------------------ +// Title: Factory Component and Object Wrappers +// +// This section defines the proxy component and object classes used by the +// factory. +//------------------------------------------------------------------------------ + +typedef class uvm_registry_common; +typedef class uvm_registry_component_creator; +typedef class uvm_registry_object_creator; + +// Class: uvm_component_registry#(T,Tname) +// Implementation of uvm_component_registry#(T,Tname), as defined by section +// 8.2.3.1 of 1800.2-2017. + +// @uvm-ieee 1800.2-2017 auto 8.2.3.1 +class uvm_component_registry #(type T=uvm_component, string Tname="") + extends uvm_object_wrapper; + typedef uvm_component_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_component_creator, T, Tname ) common_type; + + // Function -- NODOCS -- create_component + // + // Creates a component of type T having the provided ~name~ and ~parent~. + // This is an override of the method in . It is + // called by the factory after determining the type of object to create. + // You should not call this method directly. Call instead. + + // @uvm-ieee 1800.2-2017 auto 8.2.3.2.1 + virtual function uvm_component create_component (string name, + uvm_component parent); + T obj; + obj = new(name, parent); + return obj; + endfunction + + + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + + // Function -- NODOCS -- get_type_name + // + // Returns the value given by the string parameter, ~Tname~. This method + // overrides the method in . + + // @uvm-ieee 1800.2-2017 auto 8.2.3.2.2 + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + + + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + + // @uvm-ieee 1800.2-2017 auto 8.2.3.2.7 + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction + + + // Function -- NODOCS -- create + // + // Returns an instance of the component type, ~T~, represented by this proxy, + // subject to any factory overrides based on the context provided by the + // ~parent~'s full name. The ~contxt~ argument, if supplied, supersedes the + // ~parent~'s context. The new instance will have the given leaf ~name~ + // and ~parent~. + + // @uvm-ieee 1800.2-2017 auto 8.2.3.2.4 + static function T create(string name, uvm_component parent, string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + + + // Function -- NODOCS -- set_type_override + // + // Configures the factory to create an object of the type represented by + // ~override_type~ whenever a request is made to create an object of the type, + // ~T~, represented by this proxy, provided no instance override applies. The + // original type, ~T~, is typically a super class of the override type. + + // @uvm-ieee 1800.2-2017 auto 8.2.3.2.5 + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + + + // Function -- NODOCS -- set_inst_override + // + // Configures the factory to create a component of the type represented by + // ~override_type~ whenever a request is made to create an object of the type, + // ~T~, represented by this proxy, with matching instance paths. The original + // type, ~T~, is typically a super class of the override type. + // + // If ~parent~ is not specified, ~inst_path~ is interpreted as an absolute + // instance path, which enables instance overrides to be set from outside + // component classes. If ~parent~ is specified, ~inst_path~ is interpreted + // as being relative to the ~parent~'s hierarchical instance path, i.e. + // ~{parent.get_full_name(),".",inst_path}~ is the instance path that is + // registered with the override. The ~inst_path~ may contain wildcards for + // matching against multiple contexts. + + // @uvm-ieee 1800.2-2017 auto 8.2.3.2.6 + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + + // Function: set_type_alias + // Sets a type alias for this wrapper in the default factory. + // + // If this wrapper is not yet registered with a factory (see ), + // then the alias is deferred until registration occurs. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + +endclass + + +// Class: uvm_object_registry#(T,Tname) +// Implementation of uvm_object_registry#(T,Tname), as defined by section +// 8.2.4.1 of 1800.2-2017. + +// @uvm-ieee 1800.2-2017 auto 8.2.4.1 +class uvm_object_registry #(type T=uvm_object, string Tname="") + extends uvm_object_wrapper; + typedef uvm_object_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_object_creator, T, Tname ) common_type; + + // Function -- NODOCS -- create_object + // + // Creates an object of type ~T~ and returns it as a handle to a + // . This is an override of the method in . + // It is called by the factory after determining the type of object to create. + // You should not call this method directly. Call instead. + + // @uvm-ieee 1800.2-2017 auto 8.2.4.2.1 + virtual function uvm_object create_object(string name=""); + T obj; + if (name=="") obj = new(); + else obj = new(name); + return obj; + endfunction + + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + + // Function -- NODOCS -- get_type_name + // + // Returns the value given by the string parameter, ~Tname~. This method + // overrides the method in . + + // @uvm-ieee 1800.2-2017 auto 8.2.4.2.2 + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + + // + // Returns the singleton instance of this type. Type-based factory operation + // depends on there being a single proxy instance for each registered type. + + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + + + // Function -- NODOCS -- create + // + // Returns an instance of the object type, ~T~, represented by this proxy, + // subject to any factory overrides based on the context provided by the + // ~parent~'s full name. The ~contxt~ argument, if supplied, supersedes the + // ~parent~'s context. The new instance will have the given leaf ~name~, + // if provided. + + // @uvm-ieee 1800.2-2017 auto 8.2.4.2.4 + static function T create (string name="", uvm_component parent=null, + string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + + + // Function -- NODOCS -- set_type_override + // + // Configures the factory to create an object of the type represented by + // ~override_type~ whenever a request is made to create an object of the type + // represented by this proxy, provided no instance override applies. The + // original type, ~T~, is typically a super class of the override type. + + // @uvm-ieee 1800.2-2017 auto 8.2.4.2.5 + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + + + // Function -- NODOCS -- set_inst_override + // + // Configures the factory to create an object of the type represented by + // ~override_type~ whenever a request is made to create an object of the type + // represented by this proxy, with matching instance paths. The original + // type, ~T~, is typically a super class of the override type. + // + // If ~parent~ is not specified, ~inst_path~ is interpreted as an absolute + // instance path, which enables instance overrides to be set from outside + // component classes. If ~parent~ is specified, ~inst_path~ is interpreted + // as being relative to the ~parent~'s hierarchical instance path, i.e. + // ~{parent.get_full_name(),".",inst_path}~ is the instance path that is + // registered with the override. The ~inst_path~ may contain wildcards for + // matching against multiple contexts. + + // @uvm-ieee 1800.2-2017 auto 8.2.4.2.6 + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + + // Function: set_type_alias + // Sets a type alias for this wrapper in the default factory. + // + // If this wrapper is not yet registered with a factory (see ), + // then the alias is deferred until registration occurs. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + + // @uvm-ieee 1800.2-2017 auto 8.2.4.2.7 + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass + +// Class: uvm_abstract_component_registry#(T,Tname) +// Implementation of uvm_abstract_component_registry#(T,Tname), as defined by section +// 8.2.5.1.1 of 1800.2-2017. + +// @uvm-ieee 1800.2-2017 auto 8.2.5.1.1 +class uvm_abstract_component_registry #(type T=uvm_component, string Tname="") + extends uvm_object_wrapper; + typedef uvm_abstract_component_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_component_creator, T, Tname ) common_type; + + // Function -- NODOCS -- create_component + // + // Creates a component of type T having the provided ~name~ and ~parent~. + // This is an override of the method in . It is + // called by the factory after determining the type of object to create. + // You should not call this method directly. Call instead. + + // @uvm-ieee 1800.2-2017 auto 8.2.5.1.2 + virtual function uvm_component create_component (string name, + uvm_component parent); + `uvm_error( + "UVM/ABST_RGTRY/CREATE_ABSTRACT_CMPNT", + $sformatf( "Cannot create an instance of abstract class %s (with name %s and parent %s). Check for missing factory overrides for %s.", this.get_type_name(), name, parent.get_full_name(), this.get_type_name() ) + ) + return null; + endfunction + + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + + // Function -- NODOCS -- get_type_name + // + // Returns the value given by the string parameter, ~Tname~. This method + // overrides the method in . + + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + + + // Function -- NODOCS -- get + // + // Returns the singleton instance of this type. Type-based factory operation + // depends on there being a single proxy instance for each registered type. + + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + + + // Function -- NODOCS -- create + // + // Returns an instance of the component type, ~T~, represented by this proxy, + // subject to any factory overrides based on the context provided by the + // ~parent~'s full name. The ~contxt~ argument, if supplied, supersedes the + // ~parent~'s context. The new instance will have the given leaf ~name~ + // and ~parent~. + + static function T create(string name, uvm_component parent, string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + + + // Function -- NODOCS -- set_type_override + // + // Configures the factory to create an object of the type represented by + // ~override_type~ whenever a request is made to create an object of the type, + // ~T~, represented by this proxy, provided no instance override applies. The + // original type, ~T~, is typically a super class of the override type. + + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + + + // Function -- NODOCS -- set_inst_override + // + // Configures the factory to create a component of the type represented by + // ~override_type~ whenever a request is made to create an object of the type, + // ~T~, represented by this proxy, with matching instance paths. The original + // type, ~T~, is typically a super class of the override type. + // + // If ~parent~ is not specified, ~inst_path~ is interpreted as an absolute + // instance path, which enables instance overrides to be set from outside + // component classes. If ~parent~ is specified, ~inst_path~ is interpreted + // as being relative to the ~parent~'s hierarchical instance path, i.e. + // ~{parent.get_full_name(),".",inst_path}~ is the instance path that is + // registered with the override. The ~inst_path~ may contain wildcards for + // matching against multiple contexts. + + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + + // Function: set_type_alias + // Sets a type alias for this wrapper in the default factory. + // + // If this wrapper is not yet registered with a factory (see ), + // then the alias is deferred until registration occurs. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass + + +// Class: uvm_abstract_object_registry#(T,Tname) +// Implementation of uvm_abstract_object_registry#(T,Tname), as defined by section +// 8.2.5.2.1 of 1800.2-2017. + +// @uvm-ieee 1800.2-2017 auto 8.2.5.2.1 +class uvm_abstract_object_registry #(type T=uvm_object, string Tname="") + extends uvm_object_wrapper; + typedef uvm_abstract_object_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_object_creator, T, Tname ) common_type; + + // Function -- NODOCS -- create_object + // + // Creates an object of type ~T~ and returns it as a handle to a + // . This is an override of the method in . + // It is called by the factory after determining the type of object to create. + // You should not call this method directly. Call instead. + + // @uvm-ieee 1800.2-2017 auto 8.2.5.2.2 + virtual function uvm_object create_object(string name=""); + `uvm_error( + "UVM/ABST_RGTRY/CREATE_ABSTRACT_OBJ", + $sformatf( "Cannot create an instance of abstract class %s (with name %s). Check for missing factory overrides for %s.", this.get_type_name(), name, this.get_type_name() ) + ) + return null; + endfunction + + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + + // Function -- NODOCS -- get_type_name + // + // Returns the value given by the string parameter, ~Tname~. This method + // overrides the method in . + + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + + // Function -- NODOCS -- get + // + // Returns the singleton instance of this type. Type-based factory operation + // depends on there being a single proxy instance for each registered type. + + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + + + // Function -- NODOCS -- create + // + // Returns an instance of the object type, ~T~, represented by this proxy, + // subject to any factory overrides based on the context provided by the + // ~parent~'s full name. The ~contxt~ argument, if supplied, supersedes the + // ~parent~'s context. The new instance will have the given leaf ~name~, + // if provided. + + static function T create (string name="", uvm_component parent=null, + string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + + + // Function -- NODOCS -- set_type_override + // + // Configures the factory to create an object of the type represented by + // ~override_type~ whenever a request is made to create an object of the type + // represented by this proxy, provided no instance override applies. The + // original type, ~T~, is typically a super class of the override type. + + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + + + // Function -- NODOCS -- set_inst_override + // + // Configures the factory to create an object of the type represented by + // ~override_type~ whenever a request is made to create an object of the type + // represented by this proxy, with matching instance paths. The original + // type, ~T~, is typically a super class of the override type. + // + // If ~parent~ is not specified, ~inst_path~ is interpreted as an absolute + // instance path, which enables instance overrides to be set from outside + // component classes. If ~parent~ is specified, ~inst_path~ is interpreted + // as being relative to the ~parent~'s hierarchical instance path, i.e. + // ~{parent.get_full_name(),".",inst_path}~ is the instance path that is + // registered with the override. The ~inst_path~ may contain wildcards for + // matching against multiple contexts. + + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + + // Function: set_type_alias + // Sets a type alias for this wrapper in the default factory. + // + // If this wrapper is not yet registered with a factory (see ), + // then the alias is deferred until registration occurs. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_registry_common #(T,Tname) +// +// This is a helper class which implements the functioanlity that is identical +// between uvm_component_registry and uvm_abstract_component_registry. +// +//------------------------------------------------------------------------------ + +class uvm_registry_common #( type Tregistry=int, type Tcreator=int, type Tcreated=int, string Tname="" ); + + typedef uvm_registry_common#(Tregistry,Tcreator,Tcreated,Tname) this_type; + local static string m__type_aliases[$]; + + static function string type_name(); + if((Tname == "") && (m__type_aliases.size() != 0)) begin + return m__type_aliases[0]; + end + return Tname; + endfunction : type_name + + virtual function string get_type_name(); + return type_name(); + endfunction + + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction : get + + static function Tcreated create(string name, uvm_component parent, string contxt); + uvm_object obj; + if (contxt == "" && parent != null) + contxt = parent.get_full_name(); + obj = Tcreator::create_by_type( Tregistry::get(), contxt, name, parent ); + if (!$cast(create, obj)) begin + string msg; + msg = {"Factory did not return a ", Tcreator::base_type_name(), " of type '",Tregistry::type_name, + "'. A component of type '",obj == null ? "null" : obj.get_type_name(), + "' was returned instead. Name=",name," Parent=", + parent==null?"null":parent.get_type_name()," contxt=",contxt}; + uvm_report_fatal("FCTTYP", msg, UVM_NONE); + end + endfunction + + static function void set_type_override (uvm_object_wrapper override_type, + bit replace); + uvm_factory factory=uvm_factory::get(); + + factory.set_type_override_by_type(Tregistry::get(),override_type,replace); + endfunction + + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent); + string full_inst_path; + uvm_factory factory=uvm_factory::get(); + + if (parent != null) begin + if (inst_path == "") + inst_path = parent.get_full_name(); + else + inst_path = {parent.get_full_name(),".",inst_path}; + end + factory.set_inst_override_by_type(Tregistry::get(),override_type,inst_path); + endfunction + + static function void set_type_alias(string alias_name); + m__type_aliases.push_back(alias_name); + m__type_aliases.sort(); + if (uvm_pkg::get_core_state() != UVM_CORE_UNINITIALIZED) begin + uvm_factory factory = uvm_factory::get(); + Tregistry rgtry = Tregistry::get(); + if (factory.is_type_registered(rgtry)) begin + factory.set_type_alias(alias_name,rgtry); + end + end + endfunction + + static function bit __deferred_init(); + Tregistry rgtry = Tregistry::get(); + // If the core is uninitialized, we defer initialization + if (uvm_pkg::get_core_state() == UVM_CORE_UNINITIALIZED) begin + uvm_pkg::uvm_deferred_init.push_back(rgtry); + end + // If the core is initialized, then we're static racing, + // initialize immediately + else begin + rgtry.initialize(); + end + return 1; + endfunction + local static bit m__initialized=__deferred_init(); + + virtual function void initialize(); + uvm_factory factory =uvm_factory::get(); + Tregistry rgtry = Tregistry::get(); + factory.register(rgtry); + // add aliases that were set before + // the wrapper was registered with the factory + foreach(m__type_aliases[i]) begin + factory.set_type_alias(m__type_aliases[i],rgtry); + end + endfunction +endclass + + +//------------------------------------------------------------------------------ +// +// The next two classes are helper classes passed as type parameters to +// uvm_registry_common. They abstract away the function calls +// uvm_factory::create_component_by_type and +// uvm_factory::create_object_by_type. Choosing between the two is handled at +// compile time.. +// +//------------------------------------------------------------------------------ + +virtual class uvm_registry_component_creator; + + static function uvm_component create_by_type( + uvm_object_wrapper obj_wrpr, + string contxt, + string name, + uvm_component parent + ); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory = cs.get_factory(); + return factory.create_component_by_type( obj_wrpr, contxt, name, parent ); + endfunction + + static function string base_type_name(); return "component"; endfunction +endclass + +virtual class uvm_registry_object_creator; + + static function uvm_object create_by_type( + uvm_object_wrapper obj_wrpr, + string contxt, + string name, + uvm_object unused + ); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory = cs.get_factory(); + unused = unused; // ... to keep linters happy. + return factory.create_object_by_type( obj_wrpr, contxt, name ); + endfunction + + static function string base_type_name(); return "object"; endfunction +endclass + + + +// Group -- NODOCS -- Usage +// +// This section describes usage for the uvm_*_registry classes. +// +// The wrapper classes are used to register lightweight proxies of objects and +// components. +// +// To register a particular component type, you need only typedef a +// specialization of its proxy class, which is typically done inside the class. +// +// For example, to register a UVM component of type ~mycomp~ +// +//| class mycomp extends uvm_component; +//| typedef uvm_component_registry #(mycomp,"mycomp") type_id; +//| endclass +// +// However, because of differences between simulators, it is necessary to use a +// macro to ensure vendor interoperability with factory registration. To +// register a UVM component of type ~mycomp~ in a vendor-independent way, you +// would write instead: +// +//| class mycomp extends uvm_component; +//| `uvm_component_utils(mycomp) +//| ... +//| endclass +// +// The <`uvm_component_utils> macro is for non-parameterized classes. In this +// example, the typedef underlying the macro specifies the ~Tname~ +// parameter as "mycomp", and ~mycomp~'s get_type_name() is defined to return +// the same. With ~Tname~ defined, you can use the factory's name-based methods to +// set overrides and create objects and components of non-parameterized types. +// +// For parameterized types, the type name changes with each specialization, so +// you cannot specify a ~Tname~ inside a parameterized class and get the behavior +// you want; the same type name string would be registered for all +// specializations of the class! (The factory would produce warnings for each +// specialization beyond the first.) To avoid the warnings and simulator +// interoperability issues with parameterized classes, you must register +// parameterized classes with a different macro. +// +// For example, to register a UVM component of type driver #(T), you +// would write: +// +//| class driver #(type T=int) extends uvm_component; +//| `uvm_component_param_utils(driver #(T)) +//| ... +//| endclass +// +// The <`uvm_component_param_utils> and <`uvm_object_param_utils> macros are used +// to register parameterized classes with the factory. Unlike the non-param +// versions, these macros do not specify the ~Tname~ parameter in the underlying +// uvm_component_registry typedef, and they do not define the get_type_name +// method for the user class. Consequently, you will not be able to use the +// factory's name-based methods for parameterized classes. +// +// The primary purpose for adding the factory's type-based methods was to +// accommodate registration of parameterized types and eliminate the many sources +// of errors associated with string-based factory usage. Thus, use of name-based +// lookup in is no longer recommended. + +`endif // UVM_REGISTRY_SVH diff --git a/test_regress/t/t_uvm/base/uvm_report_catcher.svh b/test_regress/t/t_uvm/base/uvm_report_catcher.svh new file mode 100644 index 0000000000..9be0e7b47b --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_report_catcher.svh @@ -0,0 +1,681 @@ +// $Id: uvm_report_catcher.svh,v 1.1.2.10 2010/04/09 15:03:25 janick Exp $ +//------------------------------------------------------------------------------ +// Copyright 2007-2018 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2018 Intel Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +`ifndef UVM_REPORT_CATCHER_SVH +`define UVM_REPORT_CATCHER_SVH + +typedef class uvm_report_object; +typedef class uvm_report_handler; +typedef class uvm_report_server; +typedef class uvm_report_catcher; + +typedef uvm_callbacks #(uvm_report_object, uvm_report_catcher) uvm_report_cb; +typedef uvm_callback_iter#(uvm_report_object, uvm_report_catcher) uvm_report_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.5*/ ; + +class sev_id_struct; + bit sev_specified ; + bit id_specified ; + uvm_severity sev ; + string id ; + bit is_on ; +endclass + +// TITLE: Report Catcher +// +// Contains debug methods in the Accellera UVM implementation not documented +// in the IEEE 1800.2-2017 LRM + + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_report_catcher +// + +// @uvm-ieee 1800.2-2017 auto 6.6.1 +virtual class uvm_report_catcher extends uvm_callback; + + `uvm_register_cb(uvm_report_object,uvm_report_catcher) + + typedef enum { UNKNOWN_ACTION, THROW, CAUGHT} action_e; + + local static uvm_report_message m_modified_report_message; + local static uvm_report_message m_orig_report_message; + + local static bit m_set_action_called; + + // Counts for the demoteds and caughts + local static int m_demoted_fatal; + local static int m_demoted_error; + local static int m_demoted_warning; + local static int m_caught_fatal; + local static int m_caught_error; + local static int m_caught_warning; + + // Flag counts + const static int DO_NOT_CATCH = 1; + const static int DO_NOT_MODIFY = 2; + local static int m_debug_flags; + + local static bit do_report; + + + // Function -- NODOCS -- new + // + // Create a new report catcher. The name argument is optional, but + // should generally be provided to aid in debugging. + + // @uvm-ieee 1800.2-2017 auto 6.6.2 + function new(string name = "uvm_report_catcher"); + super.new(name); + do_report = 1; + endfunction + + // Group -- NODOCS -- Current Message State + + // Function -- NODOCS -- get_client + // + // Returns the that has generated the message that + // is currently being processed. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.1 + function uvm_report_object get_client(); + return m_modified_report_message.get_report_object(); + endfunction + + // Function -- NODOCS -- get_severity + // + // Returns the of the message that is currently being + // processed. If the severity was modified by a previously executed + // catcher object (which re-threw the message), then the returned + // severity is the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.2 + function uvm_severity get_severity(); + return this.m_modified_report_message.get_severity(); + endfunction + + // Function -- NODOCS -- get_context + // + // Returns the context name of the message that is currently being + // processed. This is typically the full hierarchical name of the component + // that issued the message. However, if user-defined context is set from + // a uvm_report_message, the user-defined context will be returned. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.3 + function string get_context(); + string context_str; + + context_str = this.m_modified_report_message.get_context(); + if (context_str == "") begin + uvm_report_handler rh = this.m_modified_report_message.get_report_handler(); + context_str = rh.get_full_name(); + end + + return context_str; + endfunction + + // Function -- NODOCS -- get_verbosity + // + // Returns the verbosity of the message that is currently being + // processed. If the verbosity was modified by a previously executed + // catcher (which re-threw the message), then the returned + // verbosity is the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.4 + function int get_verbosity(); + return this.m_modified_report_message.get_verbosity(); + endfunction + + // Function -- NODOCS -- get_id + // + // Returns the string id of the message that is currently being + // processed. If the id was modified by a previously executed + // catcher (which re-threw the message), then the returned + // id is the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.5 + function string get_id(); + return this.m_modified_report_message.get_id(); + endfunction + + // Function -- NODOCS -- get_message + // + // Returns the string message of the message that is currently being + // processed. If the message was modified by a previously executed + // catcher (which re-threw the message), then the returned + // message is the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.6 + function string get_message(); + return this.m_modified_report_message.get_message(); + endfunction + + // Function -- NODOCS -- get_action + // + // Returns the of the message that is currently being + // processed. If the action was modified by a previously executed + // catcher (which re-threw the message), then the returned + // action is the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.7 + function uvm_action get_action(); + return this.m_modified_report_message.get_action(); + endfunction + + // Function -- NODOCS -- get_fname + // + // Returns the file name of the message. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.8 + function string get_fname(); + return this.m_modified_report_message.get_filename(); + endfunction + + // Function -- NODOCS -- get_line + // + // Returns the line number of the message. + + // @uvm-ieee 1800.2-2017 auto 6.6.3.9 + function int get_line(); + return this.m_modified_report_message.get_line(); + endfunction + + // Function -- NODOCS -- get_element_container + // + // Returns the element container of the message. + + function uvm_report_message_element_container get_element_container(); + return this.m_modified_report_message.get_element_container(); + endfunction + + + // Group -- NODOCS -- Change Message State + + // Function -- NODOCS -- set_severity + // + // Change the severity of the message to ~severity~. Any other + // report catchers will see the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.4.1 + protected function void set_severity(uvm_severity severity); + this.m_modified_report_message.set_severity(severity); + endfunction + + // Function -- NODOCS -- set_verbosity + // + // Change the verbosity of the message to ~verbosity~. Any other + // report catchers will see the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.4.2 + protected function void set_verbosity(int verbosity); + this.m_modified_report_message.set_verbosity(verbosity); + endfunction + + // Function -- NODOCS -- set_id + // + // Change the id of the message to ~id~. Any other + // report catchers will see the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.4.3 + protected function void set_id(string id); + this.m_modified_report_message.set_id(id); + endfunction + + // Function -- NODOCS -- set_message + // + // Change the text of the message to ~message~. Any other + // report catchers will see the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.4.4 + protected function void set_message(string message); + this.m_modified_report_message.set_message(message); + endfunction + + // Function -- NODOCS -- set_action + // + // Change the action of the message to ~action~. Any other + // report catchers will see the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.4.5 + protected function void set_action(uvm_action action); + this.m_modified_report_message.set_action(action); + this.m_set_action_called = 1; + endfunction + + // Function -- NODOCS -- set_context + // + // Change the context of the message to ~context_str~. Any other + // report catchers will see the modified value. + + // @uvm-ieee 1800.2-2017 auto 6.6.4.6 + protected function void set_context(string context_str); + this.m_modified_report_message.set_context(context_str); + endfunction + + // Function -- NODOCS -- add_int + // + // Add an integral type of the name ~name~ and value ~value~ to + // the message. The required ~size~ field indicates the size of ~value~. + // The required ~radix~ field determines how to display and + // record the field. Any other report catchers will see the newly + // added element. + // + + protected function void add_int(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + this.m_modified_report_message.add_int(name, value, size, radix, action); + endfunction + + + // Function -- NODOCS -- add_string + // + // Adds a string of the name ~name~ and value ~value~ to the + // message. Any other report catchers will see the newly + // added element. + // + + protected function void add_string(string name, + string value, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + this.m_modified_report_message.add_string(name, value, action); + endfunction + + + // Function -- NODOCS -- add_object + // + // Adds a uvm_object of the name ~name~ and reference ~obj~ to + // the message. Any other report catchers will see the newly + // added element. + // + + protected function void add_object(string name, + uvm_object obj, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + this.m_modified_report_message.add_object(name, obj, action); + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + // Group -- NODOCS -- Debug + + // Function -- NODOCS -- get_report_catcher + // + // Returns the first report catcher that has ~name~. + + static function uvm_report_catcher get_report_catcher(string name); + static uvm_report_cb_iter iter = new(null); + get_report_catcher = iter.first(); + while(get_report_catcher != null) begin + if(get_report_catcher.get_name() == name) + return get_report_catcher; + get_report_catcher = iter.next(); + end + return null; + endfunction +`endif + + // Function: print_catcher + // + // Prints debug information about all of the typewide report catchers that are + // registered. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + static function void print_catcher(UVM_FILE file = 0); + string msg; + string enabled; + uvm_report_catcher catcher; + static uvm_report_cb_iter iter = new(null); + string q[$]; + + q.push_back("-------------UVM REPORT CATCHERS----------------------------\n"); + + catcher = iter.first(); + while(catcher != null) begin + if(catcher.callback_mode()) + enabled = "ON"; + else + enabled = "OFF"; + + q.push_back($sformatf("%20s : %s\n", catcher.get_name(),enabled)); + catcher = iter.next(); + end + q.push_back("--------------------------------------------------------------\n"); + + `uvm_info_context("UVM/REPORT/CATCHER",`UVM_STRING_QUEUE_STREAMING_PACK(q),UVM_LOW,uvm_root::get()) + endfunction + + // Function: debug_report_catcher + // + // Turn on report catching debug information. bits[1:0] of ~what~ enable debug features + // * bit 0 - when set to 1 -- forces catch to be ignored so that all catchers see the + // the reports. + // * bit 1 - when set to 1 -- forces the message to remain unchanged + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + static function void debug_report_catcher(int what= 0); + m_debug_flags = what; + endfunction + + // Group -- NODOCS -- Callback Interface + + // Function -- NODOCS -- catch + // + // This is the method that is called for each registered report catcher. + // There are no arguments to this function. The + // interface methods can be used to access information about the + // current message being processed. + + // @uvm-ieee 1800.2-2017 auto 6.6.5 + pure virtual function action_e catch(); + + + // Group -- NODOCS -- Reporting + + // Function -- NODOCS -- uvm_report_fatal + // + // Issues a fatal message using the current message's report object. + // This message will bypass any message catching callbacks. + + protected function void uvm_report_fatal(string id, + string message, + int verbosity, + string fname = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_FATAL, id, message, UVM_NONE, fname, line, + context_name, report_enabled_checked); + endfunction + + + // Function -- NODOCS -- uvm_report_error + // + // Issues an error message using the current message's report object. + // This message will bypass any message catching callbacks. + + protected function void uvm_report_error(string id, + string message, + int verbosity, + string fname = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_ERROR, id, message, UVM_NONE, fname, line, + context_name, report_enabled_checked); + endfunction + + + // Function -- NODOCS -- uvm_report_warning + // + // Issues a warning message using the current message's report object. + // This message will bypass any message catching callbacks. + + protected function void uvm_report_warning(string id, + string message, + int verbosity, + string fname = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_WARNING, id, message, UVM_NONE, fname, line, + context_name, report_enabled_checked); + endfunction + + + // Function -- NODOCS -- uvm_report_info + // + // Issues a info message using the current message's report object. + // This message will bypass any message catching callbacks. + + protected function void uvm_report_info(string id, + string message, + int verbosity, + string fname = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_INFO, id, message, verbosity, fname, line, + context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report + // + // Issues a message using the current message's report object. + // This message will bypass any message catching callbacks. + + protected function void uvm_report(uvm_severity severity, + string id, + string message, + int verbosity, + string fname = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + uvm_report_message l_report_message; + if (report_enabled_checked == 0) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, fname, line, context_name); + this.uvm_process_report_message(l_report_message); + endfunction + + protected function void uvm_process_report_message(uvm_report_message msg); + uvm_report_object ro = m_modified_report_message.get_report_object(); + uvm_action a = ro.get_report_action(msg.get_severity(), msg.get_id()); + + if(a) begin + string composed_message; + uvm_report_server rs = m_modified_report_message.get_report_server(); + + msg.set_report_object(ro); + msg.set_report_handler(m_modified_report_message.get_report_handler()); + msg.set_report_server(rs); + msg.set_file(ro.get_report_file_handle(msg.get_severity(), msg.get_id())); + msg.set_action(a); + + // no need to compose when neither UVM_DISPLAY nor UVM_LOG is set + if (a & (UVM_LOG|UVM_DISPLAY)) + composed_message = rs.compose_report_message(msg); + rs.execute_report_message(msg, composed_message); + end + endfunction + + + // Function -- NODOCS -- issue + // Immediately issues the message which is currently being processed. This + // is useful if the message is being ~CAUGHT~ but should still be emitted. + // + // Issuing a message will update the report_server stats, possibly multiple + // times if the message is not ~CAUGHT~. + + protected function void issue(); + string composed_message; + uvm_report_server rs = m_modified_report_message.get_report_server(); + + if(uvm_action_type'(m_modified_report_message.get_action()) != UVM_NO_ACTION) + begin + // no need to compose when neither UVM_DISPLAY nor UVM_LOG is set + if (m_modified_report_message.get_action() & (UVM_LOG|UVM_DISPLAY)) + composed_message = rs.compose_report_message(m_modified_report_message); + rs.execute_report_message(m_modified_report_message, composed_message); + end + endfunction + + + //process_all_report_catchers + //method called by report_server.report to process catchers + // + + static function int process_all_report_catchers(uvm_report_message rm); + int iter; + uvm_report_catcher catcher; + int thrown = 1; + uvm_severity orig_severity; + static bit in_catcher; + uvm_report_object l_report_object = rm.get_report_object(); + + if(in_catcher == 1) begin + return 1; + end + in_catcher = 1; + uvm_callbacks_base::m_tracing = 0; //turn off cb tracing so catcher stuff doesn't print + + orig_severity = uvm_severity'(rm.get_severity()); + m_modified_report_message = rm; + + catcher = uvm_report_cb::get_first(iter,l_report_object); + if (catcher != null) begin + if(m_debug_flags & DO_NOT_MODIFY) begin + process p = process::self(); // Keep random stability + string randstate; + if (p != null) + randstate = p.get_randstate(); + $cast(m_orig_report_message, rm.clone()); //have to clone, rm can be extended type + if (p != null) + p.set_randstate(randstate); + end + end + while(catcher != null) begin + uvm_severity prev_sev; + + if (!catcher.callback_mode()) begin + catcher = uvm_report_cb::get_next(iter,l_report_object); + continue; + end + + prev_sev = m_modified_report_message.get_severity(); + m_set_action_called = 0; + thrown = catcher.process_report_catcher(); + + // Set the action to the default action for the new severity + // if it is still at the default for the previous severity, + // unless it was explicitly set. + if (!m_set_action_called && + m_modified_report_message.get_severity() != prev_sev && + m_modified_report_message.get_action() == + l_report_object.get_report_action(prev_sev, "*@&*^*^*#")) begin + + m_modified_report_message.set_action( + l_report_object.get_report_action(m_modified_report_message.get_severity(), "*@&*^*^*#")); + end + + if(thrown == 0) begin + case(orig_severity) + UVM_FATAL: m_caught_fatal++; + UVM_ERROR: m_caught_error++; + UVM_WARNING: m_caught_warning++; + endcase + break; + end + catcher = uvm_report_cb::get_next(iter,l_report_object); + end //while + + //update counters if message was returned with demoted severity + case(orig_severity) + UVM_FATAL: + if(m_modified_report_message.get_severity() < orig_severity) + m_demoted_fatal++; + UVM_ERROR: + if(m_modified_report_message.get_severity() < orig_severity) + m_demoted_error++; + UVM_WARNING: + if(m_modified_report_message.get_severity() < orig_severity) + m_demoted_warning++; + endcase + + in_catcher = 0; + uvm_callbacks_base::m_tracing = 1; //turn tracing stuff back on + + return thrown; + endfunction + + + //process_report_catcher + //internal method to call user method + // + + local function int process_report_catcher(); + + action_e act; + + act = this.catch(); + + if(act == UNKNOWN_ACTION) + this.uvm_report_error("RPTCTHR", {"uvm_report_this.catch() in catcher instance ", + this.get_name(), " must return THROW or CAUGHT"}, UVM_NONE, `uvm_file, `uvm_line); + + if(m_debug_flags & DO_NOT_MODIFY) begin + m_modified_report_message.copy(m_orig_report_message); + end + + if(act == CAUGHT && !(m_debug_flags & DO_NOT_CATCH)) begin + return 0; + end + + return 1; + + endfunction + + + // Function -- NODOCS -- summarize + // + // This function is called automatically by . + // It prints the statistics for the active catchers. + + + static function void summarize(); + string s; + string q[$]; + if(do_report) begin + q.push_back("\n--- UVM Report catcher Summary ---\n\n\n"); + q.push_back($sformatf("Number of demoted UVM_FATAL reports :%5d\n", m_demoted_fatal)); + q.push_back($sformatf("Number of demoted UVM_ERROR reports :%5d\n", m_demoted_error)); + q.push_back($sformatf("Number of demoted UVM_WARNING reports:%5d\n", m_demoted_warning)); + q.push_back($sformatf("Number of caught UVM_FATAL reports :%5d\n", m_caught_fatal)); + q.push_back($sformatf("Number of caught UVM_ERROR reports :%5d\n", m_caught_error)); + q.push_back($sformatf("Number of caught UVM_WARNING reports :%5d\n", m_caught_warning)); + + `uvm_info_context("UVM/REPORT/CATCHER",`UVM_STRING_QUEUE_STREAMING_PACK(q),UVM_LOW,uvm_root::get()) + end + endfunction + +endclass + +`endif // UVM_REPORT_CATCHER_SVH diff --git a/test_regress/t/t_uvm/base/uvm_report_handler.svh b/test_regress/t/t_uvm/base/uvm_report_handler.svh new file mode 100644 index 0000000000..3632f8f7bd --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_report_handler.svh @@ -0,0 +1,658 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, Inc. +// Copyright 2011 Cypress Semiconductor Corp. +// Copyright 2012 Accellera Systems Initiative +// 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_REPORT_HANDLER_SVH +`define UVM_REPORT_HANDLER_SVH + +typedef class uvm_report_object; +typedef class uvm_report_server; +typedef uvm_pool#(string, uvm_action) uvm_id_actions_array; +typedef uvm_pool#(string, UVM_FILE) uvm_id_file_array; +typedef uvm_pool#(string, int) uvm_id_verbosities_array; +typedef uvm_pool#(uvm_severity, uvm_severity) uvm_sev_override_array; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_handler +// +// The uvm_report_handler is the class to which most methods in +// delegate. It stores the maximum verbosity, actions, +// and files that affect the way reports are handled. +// +// The report handler is not intended for direct use. See +// for information on the UVM reporting mechanism. +// +// The relationship between (a base class for uvm_component) +// and uvm_report_handler is typically one to one, but it can be many to one +// if several uvm_report_objects are configured to use the same +// uvm_report_handler_object. See . +// +// The relationship between uvm_report_handler and is many +// to one. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 6.4.1 +class uvm_report_handler extends uvm_object; + + // internal variables + + int m_max_verbosity_level; + + // id verbosity settings : default and severity + uvm_id_verbosities_array id_verbosities; + uvm_id_verbosities_array severity_id_verbosities[uvm_severity]; + + // actions + uvm_id_actions_array id_actions; + uvm_action severity_actions[uvm_severity]; + uvm_id_actions_array severity_id_actions[uvm_severity]; + + // severity overrides + uvm_sev_override_array sev_overrides; + uvm_sev_override_array sev_id_overrides [string]; + + // file handles : default, severity, action, (severity,id) + UVM_FILE default_file_handle; + uvm_id_file_array id_file_handles; + UVM_FILE severity_file_handles[uvm_severity]; + uvm_id_file_array severity_id_file_handles[uvm_severity]; + + + `uvm_object_utils(uvm_report_handler) + + + // Function -- NODOCS -- new + // + // Creates and initializes a new uvm_report_handler object. + + // @uvm-ieee 1800.2-2017 auto 6.4.2.1 + function new(string name = "uvm_report_handler"); + super.new(name); + initialize(); + endfunction + + + // Function -- NODOCS -- print + // + // The uvm_report_handler implements the such that + // ~print~ method provides UVM printer formatted output + // of the current configuration. A snippet of example output is shown here: + // + // |uvm_test_top uvm_report_handler - @555 + // | max_verbosity_level uvm_verbosity 32 UVM_FULL + // | id_verbosities uvm_pool 3 - + // | [ID1] uvm_verbosity 32 UVM_LOW + // | severity_id_verbosities array 4 - + // | [UVM_INFO:ID4] int 32 501 + // | id_actions uvm_pool 2 - + // | [ACT_ID] uvm_action 32 DISPLAY LOG COUNT + // | severity_actions array 4 - + // | [UVM_INFO] uvm_action 32 DISPLAY + // | [UVM_WARNING] uvm_action 32 DISPLAY RM_RECORD COUNT + // | [UVM_ERROR] uvm_action 32 DISPLAY COUNT + // | [UVM_FATAL] uvm_action 32 DISPLAY EXIT + // | default_file_handle int 32 'h1 + + // @uvm-ieee 1800.2-2017 auto 6.4.2.2 + virtual function void do_print (uvm_printer printer); + + uvm_verbosity l_verbosity; + uvm_severity l_severity; + string idx; + int l_int; + + // max verb + if ($cast(l_verbosity, m_max_verbosity_level)) + printer.print_generic("max_verbosity_level", "uvm_verbosity", 32, + l_verbosity.name()); + else + printer.print_field("max_verbosity_level", m_max_verbosity_level, 32, UVM_DEC, + ".", "int"); + + // id verbs + if(id_verbosities.first(idx)) begin + printer.print_array_header("id_verbosities",id_verbosities.num(), + "uvm_pool"); + do begin + l_int = id_verbosities.get(idx); + if ($cast(l_verbosity, l_int)) + printer.print_generic($sformatf("[%s]", idx), "uvm_verbosity", 32, + l_verbosity.name()); + else begin + string l_str; + l_str.itoa(l_int); + printer.print_generic($sformatf("[%s]", idx), "int", 32, + l_str); + end + end while(id_verbosities.next(idx)); + printer.print_array_footer(); + end + + // sev and id verbs + if(severity_id_verbosities.size() != 0) begin + int _total_cnt; + foreach (severity_id_verbosities[l_severity]) + _total_cnt += severity_id_verbosities[l_severity].num(); + printer.print_array_header("severity_id_verbosities", _total_cnt, + "array"); + if(severity_id_verbosities.first(l_severity)) begin + do begin + uvm_id_verbosities_array id_v_ary = severity_id_verbosities[l_severity]; + if(id_v_ary.first(idx)) + do begin + l_int = id_v_ary.get(idx); + if ($cast(l_verbosity, l_int)) + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_verbosity", 32, l_verbosity.name()); + else begin + string l_str; + l_str.itoa(l_int); + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "int", 32, l_str); + end + end while(id_v_ary.next(idx)); + end while(severity_id_verbosities.next(l_severity)); + end + printer.print_array_footer(); + end + + // id actions + if(id_actions.first(idx)) begin + printer.print_array_header("id_actions",id_actions.num(), + "uvm_pool"); + do begin + l_int = id_actions.get(idx); + printer.print_generic($sformatf("[%s]", idx), "uvm_action", 32, + format_action(l_int)); + end while(id_actions.next(idx)); + printer.print_array_footer(); + end + + // severity actions + if(severity_actions.first(l_severity)) begin + printer.print_array_header("severity_actions",4,"array"); + do begin + printer.print_generic($sformatf("[%s]", l_severity.name()), "uvm_action", 32, + format_action(severity_actions[l_severity])); + end while(severity_actions.next(l_severity)); + printer.print_array_footer(); + end + + // sev and id actions + if(severity_id_actions.size() != 0) begin + int _total_cnt; + foreach (severity_id_actions[l_severity]) + _total_cnt += severity_id_actions[l_severity].num(); + printer.print_array_header("severity_id_actions", _total_cnt, + "array"); + if(severity_id_actions.first(l_severity)) begin + do begin + uvm_id_actions_array id_a_ary = severity_id_actions[l_severity]; + if(id_a_ary.first(idx)) + do begin + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_action", 32, format_action(id_a_ary.get(idx))); + end while(id_a_ary.next(idx)); + end while(severity_id_actions.next(l_severity)); + end + printer.print_array_footer(); + end + + // sev overrides + if(sev_overrides.first(l_severity)) begin + printer.print_array_header("sev_overrides",sev_overrides.num(), + "uvm_pool"); + do begin + uvm_severity l_severity_new = sev_overrides.get(l_severity); + printer.print_generic($sformatf("[%s]", l_severity.name()), + "uvm_severity", 32, l_severity_new.name()); + end while(sev_overrides.next(l_severity)); + printer.print_array_footer(); + end + + // sev and id overrides + if(sev_id_overrides.size() != 0) begin + int _total_cnt; + foreach (sev_id_overrides[idx]) + _total_cnt += sev_id_overrides[idx].num(); + printer.print_array_header("sev_id_overrides", _total_cnt, + "array"); + if(sev_id_overrides.first(idx)) begin + do begin + uvm_sev_override_array sev_o_ary = sev_id_overrides[idx]; + if(sev_o_ary.first(l_severity)) + do begin + uvm_severity new_sev = sev_o_ary.get(l_severity); + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_severity", 32, new_sev.name()); + end while(sev_o_ary.next(l_severity)); + end while(sev_id_overrides.next(idx)); + end + printer.print_array_footer(); + end + + // default file handle + printer.print_field("default_file_handle", default_file_handle, 32, UVM_HEX, + ".", "int"); + + // id files + if(id_file_handles.first(idx)) begin + printer.print_array_header("id_file_handles",id_file_handles.num(), + "uvm_pool"); + do begin + printer.print_field($sformatf("[%s]", idx), id_file_handles.get(idx), 32, + UVM_HEX, ".", "UVM_FILE"); + end while(id_file_handles.next(idx)); + printer.print_array_footer(); + end + + // severity files + if(severity_file_handles.first(l_severity)) begin + printer.print_array_header("severity_file_handles",4,"array"); + do begin + printer.print_field($sformatf("[%s]", l_severity.name()), + severity_file_handles[l_severity], 32, UVM_HEX, ".", "UVM_FILE"); + end while(severity_file_handles.next(l_severity)); + printer.print_array_footer(); + end + + // sev and id files + if(severity_id_file_handles.size() != 0) begin + int _total_cnt; + foreach (severity_id_file_handles[l_severity]) + _total_cnt += severity_id_file_handles[l_severity].num(); + printer.print_array_header("severity_id_file_handles", _total_cnt, + "array"); + if(severity_id_file_handles.first(l_severity)) begin + do begin + uvm_id_file_array id_f_ary = severity_id_file_handles[l_severity]; + if(id_f_ary.first(idx)) + do begin + printer.print_field($sformatf("[%s:%s]", l_severity.name(), idx), + id_f_ary.get(idx), 32, UVM_HEX, ".", "UVM_FILE"); + end while(id_f_ary.next(idx)); + end while(severity_id_file_handles.next(l_severity)); + end + printer.print_array_footer(); + end + + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Message Processing + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- process_report_message + // + // This is the common handler method used by the four core reporting methods + // (e.g. ) in . + + // @uvm-ieee 1800.2-2017 auto 6.4.7 + virtual function void process_report_message(uvm_report_message report_message); + process p = process::self(); + uvm_report_server srvr = uvm_report_server::get_server(); + string id = report_message.get_id(); + uvm_severity severity = report_message.get_severity(); + + // Check for severity overrides and apply them before calling the server. + // An id specific override has precedence over a generic severity override. + if(sev_id_overrides.exists(id)) begin + if(sev_id_overrides[id].exists(uvm_severity'(severity))) begin + severity = sev_id_overrides[id].get(severity); + report_message.set_severity(severity); + end + end + else begin + if(sev_overrides.exists(severity)) begin + severity = sev_overrides.get(severity); + report_message.set_severity(severity); + end + end + report_message.set_file(get_file_handle(severity, id)); + report_message.set_report_handler(this); + report_message.set_action(get_action(severity, id)); + srvr.process_report_message(report_message); + + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Convenience Methods + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- format_action + // + // Returns a string representation of the ~action~, e.g., "DISPLAY". + + static function string format_action(uvm_action action); + string s; + + if(uvm_action_type'(action) == UVM_NO_ACTION) begin + s = "NO ACTION"; + end + else begin + s = ""; + if(action & UVM_DISPLAY) s = {s, "DISPLAY "}; + if(action & UVM_LOG) s = {s, "LOG "}; + if(action & UVM_RM_RECORD) s = {s, "RM_RECORD "}; + if(action & UVM_COUNT) s = {s, "COUNT "}; + if(action & UVM_CALL_HOOK) s = {s, "CALL_HOOK "}; + if(action & UVM_EXIT) s = {s, "EXIT "}; + if(action & UVM_STOP) s = {s, "STOP "}; + end + + return s; + endfunction + + + // Function- initialize + // + // Internal method for initializing report handler. + + function void initialize(); + + set_default_file(0); + m_max_verbosity_level = UVM_MEDIUM; + + id_actions=new(); + id_verbosities=new(); + id_file_handles=new(); + sev_overrides=new(); + + set_severity_action(UVM_INFO, UVM_DISPLAY); + set_severity_action(UVM_WARNING, UVM_DISPLAY); + set_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_COUNT); + set_severity_action(UVM_FATAL, UVM_DISPLAY | UVM_EXIT); + + set_severity_file(UVM_INFO, default_file_handle); + set_severity_file(UVM_WARNING, default_file_handle); + set_severity_file(UVM_ERROR, default_file_handle); + set_severity_file(UVM_FATAL, default_file_handle); + + endfunction + + + // Function- get_severity_id_file + // + // Return the file id based on the severity and the id + + local function UVM_FILE get_severity_id_file(uvm_severity severity, string id); + + uvm_id_file_array array; + + if(severity_id_file_handles.exists(severity)) begin + array = severity_id_file_handles[severity]; + if(array.exists(id)) + return array.get(id); + end + + + if(id_file_handles.exists(id)) + return id_file_handles.get(id); + + if(severity_file_handles.exists(severity)) + return severity_file_handles[severity]; + + return default_file_handle; + + endfunction + + + // Function- set_verbosity_level + // + // Internal method called by uvm_report_object. + + // @uvm-ieee 1800.2-2017 auto 6.4.3.2 + function void set_verbosity_level(int verbosity_level); + m_max_verbosity_level = verbosity_level; + endfunction + + + // Function- get_verbosity_level + // + // Returns the verbosity associated with the given ~severity~ and ~id~. + // + // First, if there is a verbosity associated with the ~(severity,id)~ pair, + // return that. Else, if there is a verbosity associated with the ~id~, return + // that. Else, return the max verbosity setting. + + // @uvm-ieee 1800.2-2017 auto 6.4.3.1 + function int get_verbosity_level(uvm_severity severity=UVM_INFO, string id="" ); + + uvm_id_verbosities_array array; + if(severity_id_verbosities.exists(severity)) begin + array = severity_id_verbosities[severity]; + if(array.exists(id)) begin + return array.get(id); + end + end + + if(id_verbosities.exists(id)) begin + return id_verbosities.get(id); + end + + return m_max_verbosity_level; + + endfunction + + + // Function- get_action + // + // Returns the action associated with the given ~severity~ and ~id~. + // + // First, if there is an action associated with the ~(severity,id)~ pair, + // return that. Else, if there is an action associated with the ~id~, return + // that. Else, if there is an action associated with the ~severity~, return + // that. Else, return the default action associated with the ~severity~. + + // @uvm-ieee 1800.2-2017 auto 6.4.4.1 + function uvm_action get_action(uvm_severity severity, string id); + + uvm_id_actions_array array; + if(severity_id_actions.exists(severity)) begin + array = severity_id_actions[severity]; + if(array.exists(id)) + return array.get(id); + end + + if(id_actions.exists(id)) + return id_actions.get(id); + + return severity_actions[severity]; + + endfunction + + + // Function- get_file_handle + // + // Returns the file descriptor associated with the given ~severity~ and ~id~. + // + // First, if there is a file handle associated with the ~(severity,id)~ pair, + // return that. Else, if there is a file handle associated with the ~id~, return + // that. Else, if there is an file handle associated with the ~severity~, return + // that. Else, return the default file handle. + + // @uvm-ieee 1800.2-2017 auto 6.4.5.1 + function UVM_FILE get_file_handle(uvm_severity severity, string id); + UVM_FILE file; + + file = get_severity_id_file(severity, id); + if (file != 0) + return file; + + if (id_file_handles.exists(id)) begin + file = id_file_handles.get(id); + if (file != 0) + return file; + end + + if (severity_file_handles.exists(severity)) begin + file = severity_file_handles[severity]; + if(file != 0) + return file; + end + + return default_file_handle; + endfunction + + + // Function- set_severity_action + // Function- set_id_action + // Function- set_severity_id_action + // Function- set_id_verbosity + // Function- set_severity_id_verbosity + // + // Internal methods called by uvm_report_object. + + // @uvm-ieee 1800.2-2017 auto 6.4.4.2 + function void set_severity_action(input uvm_severity severity, + input uvm_action action); + severity_actions[severity] = action; + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.4.2 + function void set_id_action(input string id, input uvm_action action); + id_actions.add(id, action); + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.4.2 + function void set_severity_id_action(uvm_severity severity, + string id, + uvm_action action); + if(!severity_id_actions.exists(severity)) + severity_id_actions[severity] = new; + severity_id_actions[severity].add(id,action); + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.3.3 + function void set_id_verbosity(input string id, input int verbosity); + id_verbosities.add(id, verbosity); + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.3.3 + function void set_severity_id_verbosity(uvm_severity severity, + string id, + int verbosity); + if(!severity_id_verbosities.exists(severity)) + severity_id_verbosities[severity] = new; + severity_id_verbosities[severity].add(id,verbosity); + endfunction + + // Function- set_default_file + // Function- set_severity_file + // Function- set_id_file + // Function- set_severity_id_file + // + // Internal methods called by uvm_report_object. + + // @uvm-ieee 1800.2-2017 auto 6.4.5.2 + function void set_default_file (UVM_FILE file); + default_file_handle = file; + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.5.2 + function void set_severity_file (uvm_severity severity, UVM_FILE file); + severity_file_handles[severity] = file; + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.5.2 + function void set_id_file (string id, UVM_FILE file); + id_file_handles.add(id, file); + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.5.2 + function void set_severity_id_file(uvm_severity severity, + string id, UVM_FILE file); + if(!severity_id_file_handles.exists(severity)) + severity_id_file_handles[severity] = new; + severity_id_file_handles[severity].add(id, file); + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.6 + function void set_severity_override(uvm_severity cur_severity, + uvm_severity new_severity); + sev_overrides.add(cur_severity, new_severity); + endfunction + + // @uvm-ieee 1800.2-2017 auto 6.4.6 + function void set_severity_id_override(uvm_severity cur_severity, + string id, + uvm_severity new_severity); + // has precedence over set_severity_override + // silently override previous setting + uvm_sev_override_array arr; + if(!sev_id_overrides.exists(id)) + sev_id_overrides[id] = new; + + sev_id_overrides[id].add(cur_severity, new_severity); + endfunction + + + + // Function- report + // + // This is the common handler method used by the four core reporting methods + // (e.g., uvm_report_error) in . + + virtual function void report( + uvm_severity severity, + string name, + string id, + string message, + int verbosity_level=UVM_MEDIUM, + string filename="", + int line=0, + uvm_report_object client=null + ); + + bit l_report_enabled = 0; + uvm_report_message l_report_message; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + if (!uvm_report_enabled(verbosity_level, UVM_INFO, id)) + return; + + if (client==null) + client = cs.get_root(); + + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity_level, filename, line, name); + l_report_message.set_report_object(client); + l_report_message.set_action(get_action(severity,id)); + process_report_message(l_report_message); + + endfunction + +endclass : uvm_report_handler + +`endif //UVM_REPORT_HANDLER_SVH diff --git a/test_regress/t/t_uvm/base/uvm_report_message.svh b/test_regress/t/t_uvm/base/uvm_report_message.svh new file mode 100644 index 0000000000..cc9fcc5074 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_report_message.svh @@ -0,0 +1,975 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014-2018 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +`ifndef UVM_REPORT_MESSAGE_SVH +`define UVM_REPORT_MESSAGE_SVH + + +typedef class uvm_report_server; +typedef class uvm_report_handler; +typedef class uvm_root; + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_message_element_base +// +// Base class for report message element. Defines common interface. +// +//------------------------------------------------------------------------------ + +virtual class uvm_report_message_element_base; + protected uvm_action _action; + protected string _name; + + + // Function -- NODOCS -- get_name + // + + virtual function string get_name(); + return _name; + endfunction + + // Function -- NODOCS -- set_name + // + // Get or set the name of the element + // + + virtual function void set_name(string name); + _name = name; + endfunction + + + // Function -- NODOCS -- get_action + // + + virtual function uvm_action get_action(); + return _action; + endfunction + + // Function -- NODOCS -- set_action + // + // Get or set the authorized action for the element + // + + virtual function void set_action(uvm_action action); + _action = action; + endfunction + + + function void print(uvm_printer printer); + if (_action & (UVM_LOG | UVM_DISPLAY)) + do_print(printer); + endfunction : print + function void record(uvm_recorder recorder); + if (_action & UVM_RM_RECORD) + do_record(recorder); + endfunction : record + function void copy(uvm_report_message_element_base rhs); + do_copy(rhs); + endfunction : copy + function uvm_report_message_element_base clone(); + return do_clone(); + endfunction : clone + + pure virtual function void do_print(uvm_printer printer); + pure virtual function void do_record(uvm_recorder recorder); + pure virtual function void do_copy(uvm_report_message_element_base rhs); + pure virtual function uvm_report_message_element_base do_clone(); + +endclass : uvm_report_message_element_base + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_message_int_element +// +// Message element class for integral type +// +//------------------------------------------------------------------------------ + +class uvm_report_message_int_element extends uvm_report_message_element_base; + typedef uvm_report_message_int_element this_type; + + protected uvm_bitstream_t _val; + protected int _size; + protected uvm_radix_enum _radix; + + // Function -- NODOCS -- get_value + // + + virtual function uvm_bitstream_t get_value(output int size, + output uvm_radix_enum radix); + size = _size; + radix = _radix; + return _val; + endfunction + + + // Function -- NODOCS -- set_value + // + // Get or set the value (integral type) of the element, with size and radix + // + + virtual function void set_value(uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + _size = size; + _radix = radix; + _val = value; + endfunction + + + virtual function void do_print(uvm_printer printer); + printer.print_field(_name, _val, _size, _radix); + endfunction : do_print + + virtual function void do_record(uvm_recorder recorder); + recorder.record_field(_name, _val, _size, _radix); + endfunction : do_record + + virtual function void do_copy(uvm_report_message_element_base rhs); + this_type _rhs; + $cast(_rhs, rhs); + _name = _rhs._name; + _val = _rhs._val; + _size = _rhs._size; + _radix = _rhs._radix; + _action = rhs._action; + endfunction : do_copy + + virtual function uvm_report_message_element_base do_clone(); + this_type tmp = new; + tmp.copy(this); + return tmp; + endfunction : do_clone +endclass : uvm_report_message_int_element + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_message_string_element +// +// Message element class for string type +// +//------------------------------------------------------------------------------ + +class uvm_report_message_string_element extends uvm_report_message_element_base; + typedef uvm_report_message_string_element this_type; + protected string _val; + + + // Function -- NODOCS -- get_value + // + + virtual function string get_value(); + return _val; + endfunction + + // Function -- NODOCS -- set_value + // + // Get or set the value (string type) of the element + // + + virtual function void set_value(string value); + _val = value; + endfunction + + + virtual function void do_print(uvm_printer printer); + printer.print_string(_name, _val); + endfunction : do_print + + virtual function void do_record(uvm_recorder recorder); + recorder.record_string(_name, _val); + endfunction : do_record + + virtual function void do_copy(uvm_report_message_element_base rhs); + this_type _rhs; + $cast(_rhs, rhs); + _name = _rhs._name; + _val = _rhs._val; + _action = rhs._action; + endfunction : do_copy + + virtual function uvm_report_message_element_base do_clone(); + this_type tmp = new; + tmp.copy(this); + return tmp; + endfunction : do_clone +endclass : uvm_report_message_string_element + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_message_object_element +// +// Message element class for object type +// +//------------------------------------------------------------------------------ + +class uvm_report_message_object_element extends uvm_report_message_element_base; + typedef uvm_report_message_object_element this_type; + protected uvm_object _val; + + + // Function -- NODOCS -- get_value + // + // Get the value (object reference) of the element + // + + virtual function uvm_object get_value(); + return _val; + endfunction + + // Function -- NODOCS -- set_value + // + // Get or set the value (object reference) of the element + // + + virtual function void set_value(uvm_object value); + _val = value; + endfunction + + + virtual function void do_print(uvm_printer printer); + printer.print_object(_name, _val); + endfunction : do_print + + virtual function void do_record(uvm_recorder recorder); + recorder.record_object(_name, _val); + endfunction : do_record + + virtual function void do_copy(uvm_report_message_element_base rhs); + this_type _rhs; + $cast(_rhs, rhs); + _name = _rhs._name; + _val = _rhs._val; + _action = rhs._action; + endfunction : do_copy + + virtual function uvm_report_message_element_base do_clone(); + this_type tmp = new; + tmp.copy(this); + return tmp; + endfunction : do_clone +endclass : uvm_report_message_object_element + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_message_element_container +// +// A container used by report message to contain the dynamically added elements, +// with APIs to add and delete the elements. +// +//------------------------------------------------------------------------------ + +class uvm_report_message_element_container extends uvm_object; + + protected uvm_report_message_element_base elements[$]; + + `uvm_object_utils(uvm_report_message_element_container) + + // Function -- NODOCS -- new + // + // Create a new uvm_report_message_element_container object + // + + function new(string name = "element_container"); + super.new(name); + endfunction + + + // Function -- NODOCS -- size + // + // Returns the size of the container, i.e. the number of elements + // + + virtual function int size(); + return elements.size(); + endfunction + + + // Function -- NODOCS -- delete + // + // Delete the ~index~-th element in the container + // + + virtual function void delete(int index); + elements.delete(index); + endfunction + + + // Function -- NODOCS -- delete_elements + // + // Delete all the elements in the container + // + + virtual function void delete_elements(); + elements.delete(); + endfunction + + + // Function -- NODOCS -- get_elements + // + // Get all the elements from the container and put them in a queue + // + + typedef uvm_report_message_element_base queue_of_element[$]; + virtual function queue_of_element get_elements(); + return elements; + endfunction + + + // Function -- NODOCS -- add_int + // + // This method adds an integral type of the name ~name~ and value ~value~ to + // the container. The required ~size~ field indicates the size of ~value~. + // The required ~radix~ field determines how to display and + // record the field. The optional print/record bit is to specify whether + // the element will be printed/recorded. + // + + virtual function void add_int(string name, uvm_bitstream_t value, + int size, uvm_radix_enum radix, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + process p; + string rand_state; + uvm_report_message_int_element urme; + + p = process::self(); + if (p != null) + rand_state = p.get_randstate(); + urme = new(); + if (p != null) + p.set_randstate(rand_state); + + urme.set_name(name); + urme.set_value(value, size, radix); + urme.set_action(action); + elements.push_back(urme); + endfunction + + + // Function -- NODOCS -- add_string + // + // This method adds a string of the name ~name~ and value ~value~ to the + // message. The optional print/record bit is to specify whether + // the element will be printed/recorded. + // + + virtual function void add_string(string name, string value, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + process p; + string rand_state; + uvm_report_message_string_element urme; + + p = process::self(); + if (p != null) + rand_state = p.get_randstate(); + urme = new(); + if (p != null) + p.set_randstate(rand_state); + + urme.set_name(name); + urme.set_value(value); + urme.set_action(action); + elements.push_back(urme); + endfunction + + + // Function -- NODOCS -- add_object + // + // This method adds a uvm_object of the name ~name~ and reference ~obj~ to + // the message. The optional print/record bit is to specify whether + // the element will be printed/recorded. + // + + virtual function void add_object(string name, uvm_object obj, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + process p; + string rand_state; + uvm_report_message_object_element urme; + + p = process::self(); + if (p != null) + rand_state = p.get_randstate(); + urme = new(); + if (p != null) + p.set_randstate(rand_state); + + urme.set_name(name); + urme.set_value(obj); + urme.set_action(action); + elements.push_back(urme); + endfunction + + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + for(int i = 0; i < elements.size(); i++) begin + elements[i].print(printer); + end + endfunction + + virtual function void do_record(uvm_recorder recorder); + super.do_record(recorder); + for(int i = 0; i < elements.size(); i++) begin + elements[i].record(recorder); + end + endfunction + + virtual function void do_copy(uvm_object rhs); + uvm_report_message_element_container urme_container; + + super.do_copy(rhs); + + if(!$cast(urme_container, rhs) || (rhs==null)) + return; + + delete_elements(); + foreach (urme_container.elements[i]) + elements.push_back(urme_container.elements[i].clone()); + + endfunction + +endclass + + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_message +// +// The uvm_report_message is the basic UVM object message class. It provides +// the fields that are common to all messages. It also has a message element +// container and provides the APIs necessary to add integral types, strings and +// uvm_objects to the container. The report message object can be initialized +// with the common fields, and passes through the whole reporting system (i.e. +// report object, report handler, report server, report catcher, etc) as an +// object. The additional elements can be added/deleted to/from the message +// object anywhere in the reporting system, and can be printed or recorded +// along with the common fields. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 6.2.1 +class uvm_report_message extends uvm_object; + + protected uvm_report_object _report_object; + protected uvm_report_handler _report_handler; + protected uvm_report_server _report_server; + + protected uvm_severity _severity; + protected string _id; + protected string _message; + protected int _verbosity; + protected string _filename; + protected int _line; + protected string _context_name; + protected uvm_action _action; + protected UVM_FILE _file; + + // Not documented. + protected uvm_report_message_element_container _report_message_element_container; + + + // Function -- NODOCS -- new + // + // Creates a new uvm_report_message object. + // + + // @uvm-ieee 1800.2-2017 auto 6.2.2.1 + function new(string name = "uvm_report_message"); + super.new(name); + _report_message_element_container = new(); + endfunction + + + // Function -- NODOCS -- new_report_message + // + // Creates a new uvm_report_message object. + // This function is the same as new(), but keeps the random stability. + // + + // @uvm-ieee 1800.2-2017 auto 6.2.2.2 + static function uvm_report_message new_report_message(string name = "uvm_report_message"); + process p; + string rand_state; + + p = process::self(); + + if (p != null) + rand_state = p.get_randstate(); + new_report_message = new(name); + if (p != null) + p.set_randstate(rand_state); + + endfunction + + + // Function -- NODOCS -- print + // + // The uvm_report_message implements such that + // ~print~ method provides UVM printer formatted output + // of the message. A snippet of example output is shown here: + // + //| -------------------------------------------------------- + //| Name Type Size Value + //| -------------------------------------------------------- + //| uvm_report_message uvm_report_message - @532 + //| severity uvm_severity 2 UVM_INFO + //| id string 10 TEST_ID + //| message string 12 A message... + //| verbosity uvm_verbosity 32 UVM_LOW + //| filename string 7 test.sv + //| line integral 32 'd58 + //| context_name string 0 "" + //| color string 3 red + //| my_int integral 32 'd5 + //| my_string string 3 foo + //| my_obj my_class - @531 + //| foo integral 32 'd3 + //| bar string 8 hi there + + + // @uvm-ieee 1800.2-2017 auto 6.2.2.3 + virtual function void do_print(uvm_printer printer); + uvm_verbosity l_verbosity; + + super.do_print(printer); + + printer.print_generic("severity", "uvm_severity", + $bits(_severity), _severity.name()); + printer.print_string("id", _id); + printer.print_string("message",_message); + if ($cast(l_verbosity, _verbosity)) + printer.print_generic("verbosity", "uvm_verbosity", + $bits(l_verbosity), l_verbosity.name()); + else + printer.print_field("verbosity", _verbosity, $bits(_verbosity), UVM_HEX); + printer.print_string("filename", _filename); + printer.print_field("line", _line, $bits(_line), UVM_UNSIGNED); + printer.print_string("context_name", _context_name); + + if (_report_message_element_container.size() != 0) begin + uvm_report_message_element_base elements[$]; + elements = _report_message_element_container.get_elements(); + foreach (elements[i]) + elements[i].print(printer); + end + endfunction + + + `uvm_object_utils(uvm_report_message) + + + + // do_pack() not needed + // do_unpack() not needed + // do_compare() not needed + + + // Not documented. + virtual function void do_copy (uvm_object rhs); + uvm_report_message report_message; + + super.do_copy(rhs); + + if(!$cast(report_message, rhs) || (rhs==null)) + return; + + _report_object = report_message.get_report_object(); + _report_handler = report_message.get_report_handler(); + _report_server = report_message.get_report_server(); + _context_name = report_message.get_context(); + _file = report_message.get_file(); + _filename = report_message.get_filename(); + _line = report_message.get_line(); + _action = report_message.get_action(); + _severity = report_message.get_severity(); + _id = report_message.get_id(); + _message = report_message.get_message(); + _verbosity = report_message.get_verbosity(); + + _report_message_element_container.copy(report_message._report_message_element_container); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Infrastructure References + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- get_report_object + + // @uvm-ieee 1800.2-2017 auto 6.2.3.1 + virtual function uvm_report_object get_report_object(); + return _report_object; + endfunction + + // Function -- NODOCS -- set_report_object + // + // Get or set the uvm_report_object that originated the message. + + // @uvm-ieee 1800.2-2017 auto 6.2.3.1 + virtual function void set_report_object(uvm_report_object ro); + _report_object = ro; + endfunction + + + // Function -- NODOCS -- get_report_handler + + // @uvm-ieee 1800.2-2017 auto 6.2.3.2 + virtual function uvm_report_handler get_report_handler(); + return _report_handler; + endfunction + + // Function -- NODOCS -- set_report_handler + // + // Get or set the uvm_report_handler that is responsible for checking + // whether the message is enabled, should be upgraded/downgraded, etc. + + // @uvm-ieee 1800.2-2017 auto 6.2.3.2 + virtual function void set_report_handler(uvm_report_handler rh); + _report_handler = rh; + endfunction + + + // Function -- NODOCS -- get_report_server + + // @uvm-ieee 1800.2-2017 auto 6.2.3.3 + virtual function uvm_report_server get_report_server(); + return _report_server; + endfunction + + // Function -- NODOCS -- set_report_server + // + // Get or set the uvm_report_server that is responsible for servicing + // the message's actions. + + // @uvm-ieee 1800.2-2017 auto 6.2.3.3 + virtual function void set_report_server(uvm_report_server rs); + _report_server = rs; + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Message Fields + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- get_severity + + // @uvm-ieee 1800.2-2017 auto 6.2.4.1 + virtual function uvm_severity get_severity(); + return _severity; + endfunction + + // Function -- NODOCS -- set_severity + // + // Get or set the severity (UVM_INFO, UVM_WARNING, UVM_ERROR or + // UVM_FATAL) of the message. The value of this field is determined via + // the API used (`uvm_info(), `uvm_waring(), etc.) and populated for the user. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.1 + virtual function void set_severity(uvm_severity sev); + _severity = sev; + endfunction + + + // Function -- NODOCS -- get_id + + // @uvm-ieee 1800.2-2017 auto 6.2.4.2 + virtual function string get_id(); + return _id; + endfunction + + // Function -- NODOCS -- set_id + // + // Get or set the id of the message. The value of this field is + // completely under user discretion. Users are recommended to follow a + // consistent convention. Settings in the uvm_report_handler allow various + // messaging controls based on this field. See . + + // @uvm-ieee 1800.2-2017 auto 6.2.4.2 + virtual function void set_id(string id); + _id = id; + endfunction + + + // Function -- NODOCS -- get_message + + // @uvm-ieee 1800.2-2017 auto 6.2.4.3 + virtual function string get_message(); + return _message; + endfunction + + // Function -- NODOCS -- set_message + // + // Get or set the user message content string. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.3 + virtual function void set_message(string msg); + _message = msg; + endfunction + + + // Function -- NODOCS -- get_verbosity + + // @uvm-ieee 1800.2-2017 auto 6.2.4.4 + virtual function int get_verbosity(); + return _verbosity; + endfunction + + // Function -- NODOCS -- set_verbosity + // + // Get or set the message threshold value. This value is compared + // against settings in the to determine whether this + // message should be executed. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.4 + virtual function void set_verbosity(int ver); + _verbosity = ver; + endfunction + + + // Function -- NODOCS -- get_filename + + // @uvm-ieee 1800.2-2017 auto 6.2.4.5 + virtual function string get_filename(); + return _filename; + endfunction + + // Function -- NODOCS -- set_filename + // + // Get or set the file from which the message originates. This value + // is automatically populated by the messaging macros. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.5 + virtual function void set_filename(string fname); + _filename = fname; + endfunction + + + // Function -- NODOCS -- get_line + + // @uvm-ieee 1800.2-2017 auto 6.2.4.6 + virtual function int get_line(); + return _line; + endfunction + + // Function -- NODOCS -- set_line + // + // Get or set the line in the ~file~ from which the message originates. + // This value is automatically populate by the messaging macros. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.6 + virtual function void set_line(int ln); + _line = ln; + endfunction + + + // Function -- NODOCS -- get_context + + // @uvm-ieee 1800.2-2017 auto 6.2.4.7 + virtual function string get_context(); + return _context_name; + endfunction + + // Function -- NODOCS -- set_context + // + // Get or set the optional user-supplied string that is meant to convey + // the context of the message. It can be useful in scopes that are not + // inherently UVM like modules, interfaces, etc. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.7 + virtual function void set_context(string cn); + _context_name = cn; + endfunction + + + // Function -- NODOCS -- get_action + + // @uvm-ieee 1800.2-2017 auto 6.2.4.8 + virtual function uvm_action get_action(); + return _action; + endfunction + + // Function -- NODOCS -- set_action + // + // Get or set the action(s) that the uvm_report_server should perform + // for this message. This field is populated by the uvm_report_handler during + // message execution flow. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.8 + virtual function void set_action(uvm_action act); + _action = act; + endfunction + + + // Function -- NODOCS -- get_file + + // @uvm-ieee 1800.2-2017 auto 6.2.4.9 + virtual function UVM_FILE get_file(); + return _file; + endfunction + + // Function -- NODOCS -- set_file + // + // Get or set the file that the message is to be written to when the + // message's action is UVM_LOG. This field is populated by the + // uvm_report_handler during message execution flow. + + // @uvm-ieee 1800.2-2017 auto 6.2.4.9 + virtual function void set_file(UVM_FILE fl); + _file = fl; + endfunction + + + // Function -- NODOCS -- get_element_container + // + // Get the element_container of the message + + virtual function uvm_report_message_element_container get_element_container(); + return _report_message_element_container; + endfunction + + + // Function -- NODOCS -- set_report_message + // + // Set all the common fields of the report message in one shot. + // + + // @uvm-ieee 1800.2-2017 auto 6.2.4.10 + virtual function void set_report_message(uvm_severity severity, + string id, + string message, + int verbosity, + string filename, + int line, + string context_name); + this._context_name = context_name; + this._filename = filename; + this._line = line; + this._severity = severity; + this._id = id; + this._message = message; + this._verbosity = verbosity; + endfunction + + + //---------------------------------------------------------------------------- + // Group- Message Recording + //---------------------------------------------------------------------------- + + // Not documented. + virtual function void m_record_message(uvm_recorder recorder); + recorder.record_string("message", _message); + endfunction + + + // Not documented. + virtual function void m_record_core_properties(uvm_recorder recorder); + + string l_string; + uvm_verbosity l_verbosity; + + if (_context_name != "") + recorder.record_string("context_name", _context_name); + recorder.record_string("filename", _filename); + recorder.record_field("line", _line, $bits(_line), UVM_UNSIGNED); + recorder.record_string("severity", _severity.name()); + if ($cast(l_verbosity, _verbosity)) + recorder.record_string("verbosity", l_verbosity.name()); + else begin + l_string.itoa(_verbosity); + recorder.record_string("verbosity", l_string); + end + + recorder.record_string("id", _id); + m_record_message(recorder); + endfunction + + // Not documented. + virtual function void do_record(uvm_recorder recorder); + + super.do_record(recorder); + + m_record_core_properties(recorder); + _report_message_element_container.record(recorder); + + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Message Element APIs + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- add_int + // + // This method adds an integral type of the name ~name~ and value ~value~ to + // the message. The required ~size~ field indicates the size of ~value~. + // The required ~radix~ field determines how to display and + // record the field. The optional print/record bit is to specify whether + // the element will be printed/recorded. + // + + virtual function void add_int(string name, uvm_bitstream_t value, + int size, uvm_radix_enum radix, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + _report_message_element_container.add_int(name, value, size, radix, action); + endfunction + + + // Function -- NODOCS -- add_string + // + // This method adds a string of the name ~name~ and value ~value~ to the + // message. The optional print/record bit is to specify whether + // the element will be printed/recorded. + // + + virtual function void add_string(string name, string value, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + _report_message_element_container.add_string(name, value, action); + endfunction + + + // Function -- NODOCS -- add_object + // + // This method adds a uvm_object of the name ~name~ and reference ~obj~ to + // the message. The optional print/record bit is to specify whether + // the element will be printed/recorded. + // + + virtual function void add_object(string name, uvm_object obj, + uvm_action action = (UVM_LOG|UVM_RM_RECORD)); + _report_message_element_container.add_object(name, obj, action); + endfunction + +endclass + + +`endif diff --git a/test_regress/t/t_uvm/base/uvm_report_object.svh b/test_regress/t/t_uvm/base/uvm_report_object.svh index 48c0fe27a1..e06ce8352d 100644 --- a/test_regress/t/t_uvm/base/uvm_report_object.svh +++ b/test_regress/t/t_uvm/base/uvm_report_object.svh @@ -1,7 +1,530 @@ -// Copyright 2023 by Antmicro Ltd. -// SPDX-License-Identifier: Apache-2.0 +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2013 Cisco Systems, Inc. +// Copyright 2017 Verific +// 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. +//------------------------------------------------------------------------------ -// Status: STUB +`ifndef UVM_REPORT_CLIENT_SVH +`define UVM_REPORT_CLIENT_SVH +typedef class uvm_component; +typedef class uvm_env; +typedef class uvm_root; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_object +// +//------------------------------------------------------------------------------ +// +// The uvm_report_object provides an interface to the UVM reporting facility. +// Through this interface, components issue the various messages that occur +// during simulation. Users can configure what actions are taken and what +// file(s) are output for individual messages from a particular component +// or for all messages from all components in the environment. Defaults are +// applied where there is no explicit configuration. +// +// Most methods in uvm_report_object are delegated to an internal instance of a +// , which stores the reporting configuration and determines +// whether an issued message should be displayed based on that configuration. +// Then, to display a message, the report handler delegates the actual +// formatting and production of messages to a central . +// +// A report consists of an id string, severity, verbosity level, and the textual +// message itself. They may optionally include the filename and line number from +// which the message came. If the verbosity level of a report is greater than the +// configured maximum verbosity level of its report object, it is ignored. +// If a report passes the verbosity filter in effect, the report's action is +// determined. If the action includes output to a file, the configured file +// descriptor(s) are determined. +// +// Actions - can be set for (in increasing priority) severity, id, and +// (severity,id) pair. They include output to the screen , +// whether the message counters should be incremented , and +// whether a $finish should occur . +// +// Default Actions - The following provides the default actions assigned to +// each severity. These can be overridden by any of the ~set_*_action~ methods. +//| UVM_INFO - UVM_DISPLAY +//| UVM_WARNING - UVM_DISPLAY +//| UVM_ERROR - UVM_DISPLAY | UVM_COUNT +//| UVM_FATAL - UVM_DISPLAY | UVM_EXIT +// +// File descriptors - These can be set by (in increasing priority) default, +// severity level, an id, or (severity,id) pair. File descriptors are +// standard SystemVerilog file descriptors; they may refer to more than one file. +// It is the user's responsibility to open and close them. +// +// Default file handle - The default file handle is 0, which means that reports +// are not sent to a file even if a UVM_LOG attribute is set in the action +// associated with the report. This can be overridden by any of the ~set_*_file~ +// methods. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 6.3.1 class uvm_report_object extends uvm_object; + + uvm_report_handler m_rh; + + local bit m_rh_set; + local function void m_rh_init(); + if (!m_rh_set) +`ifdef VERILATOR + set_report_handler(uvm_report_handler::type_id_create(get_name())); +`else + set_report_handler(uvm_report_handler::type_id::create(get_name())); +`endif + endfunction : m_rh_init + + // Function -- NODOCS -- new + // + // Creates a new report object with the given name. This method also creates + // a new object to which most tasks are delegated. + + // @uvm-ieee 1800.2-2017 auto 6.3.2 + function new(string name = ""); + super.new(name); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Reporting + //---------------------------------------------------------------------------- + + // Function -- NODOCS -- uvm_get_report_object + // + // Returns the nearest uvm_report_object when called. From inside a + // uvm_component, the method simply returns ~this~. + // + // See also the global version of . + + // @uvm-ieee 1800.2-2017 auto 6.3.3.1 + function uvm_report_object uvm_get_report_object(); + return this; + endfunction + + // Function -- NODOCS -- uvm_report_enabled + // + // Returns 1 if the configured verbosity for this severity/id is greater than + // or equal to ~verbosity~ else returns 0. + // + // See also and the global version of + // . + + // @uvm-ieee 1800.2-2017 auto 6.3.3.2 + function int uvm_report_enabled(int verbosity, + uvm_severity severity = UVM_INFO, string id = ""); + if (get_report_verbosity_level(severity, id) < verbosity) + return 0; + return 1; + endfunction + + // Function -- NODOCS -- uvm_report + + // @uvm-ieee 1800.2-2017 auto 6.3.3.3 + virtual function void uvm_report( uvm_severity severity, + string id, + string message, + int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : + (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked =0); + uvm_report_message l_report_message; + if ((severity == UVM_INFO) && (report_enabled_checked == 0)) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, filename, line, context_name); + uvm_process_report_message(l_report_message); + endfunction + + + // Function -- NODOCS -- uvm_report_info + + // @uvm-ieee 1800.2-2017 auto 6.3.3.3 + virtual function void uvm_report_info( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + uvm_report (UVM_INFO, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report_warning + + // @uvm-ieee 1800.2-2017 auto 6.3.3.3 + virtual function void uvm_report_warning( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + uvm_report (UVM_WARNING, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report_error + + // @uvm-ieee 1800.2-2017 auto 6.3.3.3 + virtual function void uvm_report_error( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + uvm_report (UVM_ERROR, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report_fatal + // + // These are the primary reporting methods in the UVM. Using these instead + // of ~$display~ and other ad hoc approaches ensures consistent output and + // central control over where output is directed and any actions that + // result. All reporting methods have the same arguments, although each has + // a different default verbosity: + // + // id - a unique id for the report or report group that can be used + // for identification and therefore targeted filtering. You can + // configure an individual report's actions and output file(s) + // using this id string. + // + // message - the message body, preformatted if necessary to a single + // string. + // + // verbosity - the verbosity of the message, indicating its relative + // importance. If this number is less than or equal to the + // effective verbosity level, see , + // then the report is issued, subject to the configured action + // and file descriptor settings. Verbosity is ignored for + // warnings, errors, and fatals. However, if a warning, error + // or fatal is demoted to an info message using the + // , then the verbosity is taken into + // account. + // + // filename/line - (Optional) The location from which the report was issued. + // Use the predefined macros, `__FILE__ and `__LINE__. + // If specified, it is displayed in the output. + // + // context_name - (Optional) The string context from where the message is + // originating. This can be the %m of a module, a specific + // method, etc. + // + // report_enabled_checked - (Optional) This bit indicates whether the + // currently provided message has been checked as to whether + // the message should be processed. If it hasn't been checked, + // it will be checked inside the uvm_report function. + + // @uvm-ieee 1800.2-2017 auto 6.3.3.3 + virtual function void uvm_report_fatal( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + uvm_report (UVM_FATAL, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_process_report_message + // + // This method takes a preformed uvm_report_message, populates it with + // the report object and passes it to the report handler for processing. + // It is expected to be checked for verbosity and populated. + + // @uvm-ieee 1800.2-2017 auto 6.3.3.4 + virtual function void uvm_process_report_message(uvm_report_message report_message); + m_rh_init(); + report_message.set_report_object(this); + m_rh.process_report_message(report_message); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Verbosity Configuration + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- get_report_verbosity_level + // + // Gets the verbosity level in effect for this object. Reports issued + // with verbosity greater than this will be filtered out. The severity + // and tag arguments check if the verbosity level has been modified for + // specific severity/tag combinations. + + // @uvm-ieee 1800.2-2017 auto 6.3.4.1 + function int get_report_verbosity_level(uvm_severity severity=UVM_INFO, string id=""); + m_rh_init(); + return m_rh.get_verbosity_level(severity, id); + endfunction + + + // Function -- NODOCS -- get_report_max_verbosity_level + // + // Gets the maximum verbosity level in effect for this report object. + // Any report from this component whose verbosity exceeds this maximum will + // be ignored. + + // @uvm-ieee 1800.2-2017 auto 6.3.4.2 + function int get_report_max_verbosity_level(); + m_rh_init(); + return m_rh.m_max_verbosity_level; + endfunction + + + // Function -- NODOCS -- set_report_verbosity_level + // + // This method sets the maximum verbosity level for reports for this component. + // Any report from this component whose verbosity exceeds this maximum will + // be ignored. + + // @uvm-ieee 1800.2-2017 auto 6.3.4.3 + function void set_report_verbosity_level (int verbosity_level); + m_rh_init(); + m_rh.set_verbosity_level(verbosity_level); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 6.3.4.4 + function void set_report_id_verbosity (string id, int verbosity); + m_rh_init(); + m_rh.set_id_verbosity(id, verbosity); + endfunction + + // Function -- NODOCS -- set_report_severity_id_verbosity + // + // These methods associate the specified verbosity threshold with reports of the + // given ~severity~, ~id~, or ~severity-id~ pair. This threshold is compared with + // the verbosity originally assigned to the report to decide whether it gets + // processed. A verbosity threshold associated with a particular ~severity-id~ + // pair takes precedence over a verbosity threshold associated with ~id~, which + // takes precedence over a verbosity threshold associated with a ~severity~. + // + // The ~verbosity~ argument can be any integer, but is most commonly a + // predefined value, , , , + // , . + + // @uvm-ieee 1800.2-2017 auto 6.3.4.4 + function void set_report_severity_id_verbosity (uvm_severity severity, + string id, int verbosity); + m_rh_init(); + m_rh.set_severity_id_verbosity(severity, id, verbosity); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Action Configuration + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- get_report_action + // + // Gets the action associated with reports having the given ~severity~ + // and ~id~. + + // @uvm-ieee 1800.2-2017 auto 6.3.5.1 + function int get_report_action(uvm_severity severity, string id); + m_rh_init(); + return m_rh.get_action(severity,id); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 6.3.5.2 + function void set_report_severity_action (uvm_severity severity, + uvm_action action); + m_rh_init(); + m_rh.set_severity_action(severity, action); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 6.3.5.2 + function void set_report_id_action (string id, uvm_action action); + m_rh_init(); + m_rh.set_id_action(id, action); + endfunction + + // Function -- NODOCS -- set_report_severity_id_action + // + // These methods associate the specified action or actions with reports of the + // given ~severity~, ~id~, or ~severity-id~ pair. An action associated with a + // particular ~severity-id~ pair takes precedence over an action associated with + // ~id~, which takes precedence over an action associated with a ~severity~. + // + // The ~action~ argument can take the value , or it can be a + // bitwise OR of any combination of , , , + // , , and . + + // @uvm-ieee 1800.2-2017 auto 6.3.5.2 + function void set_report_severity_id_action (uvm_severity severity, + string id, uvm_action action); + m_rh_init(); + m_rh.set_severity_id_action(severity, id, action); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- File Configuration + //---------------------------------------------------------------------------- + + + // Function -- NODOCS -- get_report_file_handle + // + // Gets the file descriptor associated with reports having the given + // ~severity~ and ~id~. + + // @uvm-ieee 1800.2-2017 auto 6.3.6.1 + function int get_report_file_handle(uvm_severity severity, string id); + m_rh_init(); + return m_rh.get_file_handle(severity,id); + endfunction + + + // Function -- NODOCS -- set_report_default_file + + // @uvm-ieee 1800.2-2017 auto 6.3.6.2 + function void set_report_default_file (UVM_FILE file); + m_rh_init(); + m_rh.set_default_file(file); + endfunction + + // Function -- NODOCS -- set_report_id_file + + // @uvm-ieee 1800.2-2017 auto 6.3.6.2 + function void set_report_id_file (string id, UVM_FILE file); + m_rh_init(); + m_rh.set_id_file(id, file); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 6.3.6.2 + function void set_report_severity_file (uvm_severity severity, UVM_FILE file); + m_rh_init(); + m_rh.set_severity_file(severity, file); + endfunction + + // Function -- NODOCS -- set_report_severity_id_file + // + // These methods configure the report handler to direct some or all of its + // output to the given file descriptor. The ~file~ argument must be a + // multi-channel descriptor (mcd) or file id compatible with $fdisplay. + // + // A FILE descriptor can be associated with reports of + // the given ~severity~, ~id~, or ~severity-id~ pair. A FILE associated with + // a particular ~severity-id~ pair takes precedence over a FILE associated + // with ~id~, which take precedence over an a FILE associated with a + // ~severity~, which takes precedence over the default FILE descriptor. + // + // When a report is issued and its associated action has the UVM_LOG bit + // set, the report will be sent to its associated FILE descriptor. + // The user is responsible for opening and closing these files. + + // @uvm-ieee 1800.2-2017 auto 6.3.6.2 + function void set_report_severity_id_file (uvm_severity severity, string id, + UVM_FILE file); + m_rh_init(); + m_rh.set_severity_id_file(severity, id, file); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Override Configuration + //---------------------------------------------------------------------------- + + + + // @uvm-ieee 1800.2-2017 auto 6.3.7 + function void set_report_severity_override(uvm_severity cur_severity, + uvm_severity new_severity); + m_rh_init(); + m_rh.set_severity_override(cur_severity, new_severity); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 6.3.7 + function void set_report_severity_id_override(uvm_severity cur_severity, + string id, + uvm_severity new_severity); + m_rh_init(); + m_rh.set_severity_id_override(cur_severity, id, new_severity); + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Report Handler Configuration + //---------------------------------------------------------------------------- + + // Function -- NODOCS -- set_report_handler + // + // Sets the report handler, overwriting the default instance. This allows + // more than one component to share the same report handler. + + // @uvm-ieee 1800.2-2017 auto 6.3.8.2 + function void set_report_handler(uvm_report_handler handler); + m_rh = handler; + m_rh_set = 1; + endfunction + + + // Function -- NODOCS -- get_report_handler + // + // Returns the underlying report handler to which most reporting tasks + // are delegated. + + // @uvm-ieee 1800.2-2017 auto 6.3.8.1 + function uvm_report_handler get_report_handler(); + m_rh_init(); + return m_rh; + endfunction + + + // Function -- NODOCS -- reset_report_handler + // + // Resets the underlying report handler to its default settings. This clears + // any settings made with the ~set_report_*~ methods (see below). + + // @uvm-ieee 1800.2-2017 auto 6.3.8.3 + function void reset_report_handler; + m_rh_init(); + m_rh.initialize(); + endfunction + endclass + +`endif // UVM_REPORT_CLIENT_SVH diff --git a/test_regress/t/t_uvm/base/uvm_report_server.svh b/test_regress/t/t_uvm/base/uvm_report_server.svh new file mode 100644 index 0000000000..8943e5019d --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_report_server.svh @@ -0,0 +1,870 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2018 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013 Verilab +// Copyright 2010-2012 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2014-2017 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +`ifndef UVM_REPORT_SERVER_SVH +`define UVM_REPORT_SERVER_SVH + +typedef class uvm_report_object; + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- UVM Report Server +// +// This page covers the classes that define the UVM report server facility. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_report_server +// +// uvm_report_server is a global server that processes all of the reports +// generated by a uvm_report_handler. +// +// The ~uvm_report_server~ is an abstract class which declares many of its methods +// as ~pure virtual~. The UVM uses the class +// as its default report server implementation. +//------------------------------------------------------------------------------ + +typedef class uvm_default_report_server; +// @uvm-ieee 1800.2-2017 auto 6.5.1 +virtual class uvm_report_server extends uvm_object; + function string get_type_name(); + return "uvm_report_server"; + endfunction + function new(string name="base"); + super.new(name); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.2 + pure virtual function void set_max_quit_count(int count, bit overridable = 1); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.1 + pure virtual function int get_max_quit_count(); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.4 + pure virtual function void set_quit_count(int quit_count); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.3 + pure virtual function int get_quit_count(); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.6 + pure virtual function void set_severity_count(uvm_severity severity, int count); + + // @uvm-ieee 1800.2-2017 auto 6.5.1.5 + pure virtual function int get_severity_count(uvm_severity severity); + + // Function -- NODOCS -- set_id_count + // sets the count of already passed messages with ~id~ to ~count~ + pure virtual function void set_id_count(string id, int count); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.7 + pure virtual function int get_id_count(string id); + + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.8 + pure virtual function void get_id_set(output string q[$]); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.9 + pure virtual function void get_severity_set(output uvm_severity q[$]); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.11 + pure virtual function void set_message_database(uvm_tr_database database); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.10 + pure virtual function uvm_tr_database get_message_database(); + + + // @uvm-ieee 1800.2-2017 auto 6.5.1.12 + function void do_copy (uvm_object rhs); + uvm_report_server rhs_; + + super.do_copy(rhs); + if(!$cast(rhs_,rhs)) `uvm_error("UVM/REPORT/SERVER/RPTCOPY","cannot copy to report_server from the given datatype") + + begin + uvm_severity q[$]; + rhs_.get_severity_set(q); + foreach(q[s]) + set_severity_count(q[s],rhs_.get_severity_count(q[s])); + end + + begin + string q[$]; + rhs_.get_id_set(q); + foreach(q[s]) + set_id_count(q[s],rhs_.get_id_count(q[s])); + end + + set_message_database(rhs_.get_message_database()); + set_max_quit_count(rhs_.get_max_quit_count()); + set_quit_count(rhs_.get_quit_count()); + endfunction + + + // Function- process_report_message + // + // Main entry for uvm_report_server, combines execute_report_message and compose_report_message + + // @uvm-ieee 1800.2-2017 auto 6.5.1.13 + pure virtual function void process_report_message(uvm_report_message report_message); + + + // Function -- NODOCS -- execute_report_message + // + // Processes the provided message per the actions contained within. + // + // Expert users can overload this method to customize action processing. + + // @uvm-ieee 1800.2-2017 auto 6.5.1.15 + pure virtual function void execute_report_message(uvm_report_message report_message, + string composed_message); + + + // Function -- NODOCS -- compose_report_message + // + // Constructs the actual string sent to the file or command line + // from the severity, component name, report id, and the message itself. + // + // Expert users can overload this method to customize report formatting. + + // @uvm-ieee 1800.2-2017 auto 6.5.1.14 + pure virtual function string compose_report_message(uvm_report_message report_message, + string report_object_name = ""); + + + // Function -- NODOCS -- report_summarize + // + // Outputs statistical information on the reports issued by this central report + // server. This information will be sent to the command line if ~file~ is 0, or + // to the file descriptor ~file~ if it is not 0. + // + // The method in uvm_top calls this method. + + // @uvm-ieee 1800.2-2017 auto 6.5.1.16 + pure virtual function void report_summarize(UVM_FILE file = UVM_STDOUT); + + + // Function -- NODOCS -- set_server + // + // Sets the global report server to use for reporting. + // + // This method is provided as a convenience wrapper around + // setting the report server via the + // method. + // + // In addition to setting the server this also copies the severity/id counts + // from the current report_server to the new one + // + // | // Using the uvm_coreservice_t: + // | uvm_coreservice_t cs; + // | cs = uvm_coreservice_t::get(); + // | your_server.copy(cs.get_report_server()); + // | cs.set_report_server(your_server); + // | + // | // Not using the uvm_coreservice_t: + // | uvm_report_server::set_server(your_server); + + // @uvm-ieee 1800.2-2017 auto 6.5.1.18 + static function void set_server(uvm_report_server server); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + server.copy(cs.get_report_server()); + cs.set_report_server(server); + endfunction + + + // Function -- NODOCS -- get_server + // + // Gets the global report server used for reporting. + // + // This method is provided as a convenience wrapper + // around retrieving the report server via the + // method. + // + // | // Using the uvm_coreservice_t: + // | uvm_coreservice_t cs; + // | uvm_report_server rs; + // | cs = uvm_coreservice_t::get(); + // | rs = cs.get_report_server(); + // | + // | // Not using the uvm_coreservice_t: + // | uvm_report_server rs; + // | rs = uvm_report_server::get_server(); + // + + // @uvm-ieee 1800.2-2017 auto 6.5.1.17 + static function uvm_report_server get_server(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_report_server(); + endfunction +endclass + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_default_report_server +// +// Default implementation of the UVM report server, as defined in section +// 6.5.2 of 1800.2-2017 +// + +// @uvm-ieee 1800.2-2017 auto 6.5.2 +class uvm_default_report_server extends uvm_report_server; + + local int m_quit_count; + local int m_max_quit_count; + bit max_quit_overridable = 1; + local int m_severity_count[uvm_severity]; + protected int m_id_count[string]; + protected uvm_tr_database m_message_db; + protected uvm_tr_stream m_streams[string][string]; // ro.name,rh.name + + + // Variable: enable_report_id_count_summary + // + // A flag to enable report count summary for each ID + // + // @uvm-accellera This API is specific to the Accellera implementation, and is not being considered for contribution to 1800.2 + bit enable_report_id_count_summary=1; + + + // Variable: record_all_messages + // + // A flag to force recording of all messages (add UVM_RM_RECORD action) + // + // @uvm-accellera This API is specific to the Accellera implementation, and is not being considered for contribution to 1800.2 + bit record_all_messages = 0; + + + // Variable: show_verbosity + // + // A flag to include verbosity in the messages, e.g. + // + // "UVM_INFO(UVM_MEDIUM) file.v(3) @ 60: reporter [ID0] Message 0" + // + // @uvm-accellera This API is specific to the Accellera implementation, and is not being considered for contribution to 1800.2 + bit show_verbosity = 0; + + + // Variable: show_terminator + // + // A flag to add a terminator in the messages, e.g. + // + // "UVM_INFO file.v(3) @ 60: reporter [ID0] Message 0 -UVM_INFO" + // + bit show_terminator = 0; + + // Needed for callbacks + function string get_type_name(); + return "uvm_default_report_server"; + endfunction + + + // Function --NODOCS-- new + // + // Creates an instance of the class. + + function new(string name = "uvm_report_server"); + super.new(name); + set_max_quit_count(0); + reset_quit_count(); + reset_severity_counts(); + endfunction + + + // Function --NODOCS-- print + // + // The uvm_report_server implements the such that + // ~print~ method provides UVM printer formatted output + // of the current configuration. A snippet of example output is shown here: + // + // |uvm_report_server uvm_report_server - @13 + // | quit_count int 32 'd0 + // | max_quit_count int 32 'd5 + // | max_quit_overridable bit 1 'b1 + // | severity_count severity counts 4 - + // | [UVM_INFO] integral 32 'd4 + // | [UVM_WARNING] integral 32 'd2 + // | [UVM_ERROR] integral 32 'd50 + // | [UVM_FATAL] integral 32 'd10 + // | id_count id counts 4 - + // | [ID1] integral 32 'd1 + // | [ID2] integral 32 'd2 + // | [RNTST] integral 32 'd1 + // | enable_report_id_count_summary bit 1 'b1 + // | record_all_messages bit 1 `b0 + // | show_verbosity bit 1 `b0 + // | show_terminator bit 1 `b0 + + + // Print to show report server state + virtual function void do_print (uvm_printer printer); + + uvm_severity l_severity_count_index; + string l_id_count_index; + + printer.print_field("quit_count", m_quit_count, $bits(m_quit_count), UVM_DEC, + ".", "int"); + printer.print_field("max_quit_count", m_max_quit_count, + $bits(m_max_quit_count), UVM_DEC, ".", "int"); + printer.print_field("max_quit_overridable", max_quit_overridable, + $bits(max_quit_overridable), UVM_BIN, ".", "bit"); + + if (m_severity_count.first(l_severity_count_index)) begin + printer.print_array_header("severity_count",m_severity_count.size(),"severity counts"); + do + printer.print_field($sformatf("[%s]",l_severity_count_index.name()), + m_severity_count[l_severity_count_index], 32, UVM_DEC); + while (m_severity_count.next(l_severity_count_index)); + printer.print_array_footer(); + end + + if (m_id_count.first(l_id_count_index)) begin + printer.print_array_header("id_count",m_id_count.size(),"id counts"); + do + printer.print_field($sformatf("[%s]",l_id_count_index), + m_id_count[l_id_count_index], 32, UVM_DEC); + while (m_id_count.next(l_id_count_index)); + printer.print_array_footer(); + end + + printer.print_field("enable_report_id_count_summary", enable_report_id_count_summary, + $bits(enable_report_id_count_summary), UVM_BIN, ".", "bit"); + printer.print_field("record_all_messages", record_all_messages, + $bits(record_all_messages), UVM_BIN, ".", "bit"); + printer.print_field("show_verbosity", show_verbosity, + $bits(show_verbosity), UVM_BIN, ".", "bit"); + printer.print_field("show_terminator", show_terminator, + $bits(show_terminator), UVM_BIN, ".", "bit"); + + endfunction + + + //---------------------------------------------------------------------------- + // Group --NODOCS-- Quit Count + //---------------------------------------------------------------------------- + + + // Function --NODOCS-- get_max_quit_count + + function int get_max_quit_count(); + return m_max_quit_count; + endfunction + + // Function --NODOCS-- set_max_quit_count + // + // Get or set the maximum number of COUNT actions that can be tolerated + // before a UVM_EXIT action is taken. The default is 0, which specifies + // no maximum. + + function void set_max_quit_count(int count, bit overridable = 1); + if (max_quit_overridable == 0) begin + uvm_report_info("NOMAXQUITOVR", + $sformatf("The max quit count setting of %0d is not overridable to %0d due to a previous setting.", + m_max_quit_count, count), UVM_NONE); + return; + end + max_quit_overridable = overridable; + m_max_quit_count = count < 0 ? 0 : count; + endfunction + + + // Function --NODOCS-- get_quit_count + + function int get_quit_count(); + return m_quit_count; + endfunction + + // Function --NODOCS-- set_quit_count + + function void set_quit_count(int quit_count); + m_quit_count = quit_count < 0 ? 0 : quit_count; + endfunction + + // Function --NODOCS-- incr_quit_count + + function void incr_quit_count(); + m_quit_count++; + endfunction + + // Function --NODOCS-- reset_quit_count + // + // Set, get, increment, or reset to 0 the quit count, i.e., the number of + // COUNT actions issued. + + function void reset_quit_count(); + m_quit_count = 0; + endfunction + + // Function --NODOCS-- is_quit_count_reached + // + // If is_quit_count_reached returns 1, then the quit counter has reached + // the maximum. + + function bit is_quit_count_reached(); + return (m_quit_count >= m_max_quit_count); + endfunction + + + //---------------------------------------------------------------------------- + // Group --NODOCS-- Severity Count + //---------------------------------------------------------------------------- + + + // Function --NODOCS-- get_severity_count + + function int get_severity_count(uvm_severity severity); + return m_severity_count[severity]; + endfunction + + // Function --NODOCS-- set_severity_count + + function void set_severity_count(uvm_severity severity, int count); + m_severity_count[severity] = count < 0 ? 0 : count; + endfunction + + // Function --NODOCS-- incr_severity_count + + function void incr_severity_count(uvm_severity severity); + m_severity_count[severity]++; + endfunction + + // Function --NODOCS-- reset_severity_counts + // + // Set, get, or increment the counter for the given severity, or reset + // all severity counters to 0. + + function void reset_severity_counts(); + uvm_severity s; + s = s.first(); + forever begin + m_severity_count[s] = 0; + if(s == s.last()) break; + s = s.next(); + end + endfunction + + + //---------------------------------------------------------------------------- + // Group --NODOCS-- id Count + //---------------------------------------------------------------------------- + + + // Function --NODOCS-- get_id_count + + function int get_id_count(string id); + if(m_id_count.exists(id)) + return m_id_count[id]; + return 0; + endfunction + + // Function --NODOCS-- set_id_count + + function void set_id_count(string id, int count); + m_id_count[id] = count < 0 ? 0 : count; + endfunction + + // Function --NODOCS-- incr_id_count + // + // Set, get, or increment the counter for reports with the given id. + + function void incr_id_count(string id); + if(m_id_count.exists(id)) + m_id_count[id]++; + else + m_id_count[id] = 1; + endfunction + + //---------------------------------------------------------------------------- + // Group --NODOCS-- message recording + // + // The ~uvm_default_report_server~ will record messages into the message + // database, using one transaction per message, and one stream per report + // object/handler pair. + // + //---------------------------------------------------------------------------- + + // Function --NODOCS-- set_message_database + // sets the used for recording messages + virtual function void set_message_database(uvm_tr_database database); + m_message_db = database; + endfunction : set_message_database + + // Function --NODOCS-- get_message_database + // returns the used for recording messages + // + virtual function uvm_tr_database get_message_database(); + return m_message_db; + endfunction : get_message_database + + + virtual function void get_severity_set(output uvm_severity q[$]); + foreach(m_severity_count[idx]) + q.push_back(idx); + endfunction + + + virtual function void get_id_set(output string q[$]); + foreach(m_id_count[idx]) + q.push_back(idx); + endfunction + + + // Function- f_display + // + // This method sends string severity to the command line if file is 0 and to + // the file(s) specified by file if it is not 0. + + function void f_display(UVM_FILE file, string str); + if (file == 0) + $display("%s", str); + else + $fdisplay(file, "%s", str); + endfunction + + + // Function- process_report_message + // + // + + virtual function void process_report_message(uvm_report_message report_message); + + uvm_report_handler l_report_handler = report_message.get_report_handler(); + process p = process::self(); + bit report_ok = 1; + + // Set the report server for this message + report_message.set_report_server(this); + + if(report_ok) + report_ok = uvm_report_catcher::process_all_report_catchers(report_message); + + if(uvm_action_type'(report_message.get_action()) == UVM_NO_ACTION) + report_ok = 0; + + if(report_ok) begin + string m; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + // give the global server a chance to intercept the calls + uvm_report_server svr = cs.get_report_server(); + + // no need to compose when neither UVM_DISPLAY nor UVM_LOG is set + if (report_message.get_action() & (UVM_LOG|UVM_DISPLAY)) + m = svr.compose_report_message(report_message); + + svr.execute_report_message(report_message, m); + end + + endfunction + + + //---------------------------------------------------------------------------- + // Group --NODOCS-- Message Processing + //---------------------------------------------------------------------------- + + + // Function --NODOCS-- execute_report_message + // + // Processes the provided message per the actions contained within. + // + // Expert users can overload this method to customize action processing. + + virtual function void execute_report_message(uvm_report_message report_message, + string composed_message); + + process p = process::self(); + + // Update counts + incr_severity_count(report_message.get_severity()); + incr_id_count(report_message.get_id()); + + if (record_all_messages) + report_message.set_action(report_message.get_action() | UVM_RM_RECORD); + + // UVM_RM_RECORD action + if(report_message.get_action() & UVM_RM_RECORD) begin + uvm_tr_stream stream; + uvm_report_object ro = report_message.get_report_object(); + uvm_report_handler rh = report_message.get_report_handler(); + + // Check for pre-existing stream + if (m_streams.exists(ro.get_name()) && (m_streams[ro.get_name()].exists(rh.get_name()))) + stream = m_streams[ro.get_name()][rh.get_name()]; + + // If no pre-existing stream (or for some reason pre-existing stream was ~null~) + if (stream == null) begin + uvm_tr_database db; + + // Grab the database + db = get_message_database(); + + // If database is ~null~, use the default database + if (db == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + db = cs.get_default_tr_database(); + end + if (db != null) begin + // Open the stream. Name=report object name, scope=report handler name, type=MESSAGES + stream = db.open_stream(ro.get_name(), rh.get_name(), "MESSAGES"); + // Save off the openned stream + m_streams[ro.get_name()][rh.get_name()] = stream; + end + end + if (stream != null) begin + uvm_recorder recorder = stream.open_recorder(report_message.get_name(),,report_message.get_type_name()); + if (recorder != null) begin + report_message.record(recorder); + recorder.free(); + end + end + end + + // DISPLAY action + if(report_message.get_action() & UVM_DISPLAY) + $display("%s", composed_message); + + // LOG action + // if log is set we need to send to the file but not resend to the + // display. So, we need to mask off stdout for an mcd or we need + // to ignore the stdout file handle for a file handle. + if(report_message.get_action() & UVM_LOG) + if( (report_message.get_file() == 0) || + (report_message.get_file() != 32'h8000_0001) ) begin //ignore stdout handle + UVM_FILE tmp_file = report_message.get_file(); + if((report_message.get_file() & 32'h8000_0000) == 0) begin //is an mcd so mask off stdout + tmp_file = report_message.get_file() & 32'hffff_fffe; + end + f_display(tmp_file, composed_message); + end + + // Process the UVM_COUNT action + if(report_message.get_action() & UVM_COUNT) begin + if(get_max_quit_count() != 0) begin + incr_quit_count(); + // If quit count is reached, add the UVM_EXIT action. + if(is_quit_count_reached()) begin + report_message.set_action(report_message.get_action() | UVM_EXIT); + end + end + end + + // Process the UVM_EXIT action + if(report_message.get_action() & UVM_EXIT) begin + uvm_root l_root; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + l_root = cs.get_root(); + l_root.die(); + end + + // Process the UVM_STOP action + if (report_message.get_action() & UVM_STOP) + $stop; + + endfunction + + + // Function: compose_report_message + // + // Constructs the actual string sent to the file or command line + // from the report message. + // + // The return value is constructed by concatenating the following strings in order, + // with spaces between. + // + // Severity and verbosity - If is '1', then this value is the concatenation + // of {S1,"(",S2,")"}, where ~S1~ is the severity of the message as + // returned by , and ~S2~ is the + // verbosity of the message, as returned by . + // If is '0', then this value is simply the severity + // of the message. + // + // File name and line - If returns an empty string (""), + // then this value is the empty string (""). Otherwise + // this string is formatted as "%s(%0d)", where ~%s~ is the file + // name, and ~%0d~ is the line number. + // + // Timestamp - This value is the concatenation of {"@",TIME,":"}, where ~TIME~ is determined by formatting + // ~$time~ as "%0t". Note that ~$time~ is being resolved inside of the scope. + // + // Full report context - If , returns an empty string (""), then + // this value is the full name of the report object returned by + // . Otherwise this + // value is the the concatenation of {S1,"@@",S2}, where ~S1~ is the full + // name of the report object for the message, and ~S2~ is + // the context string. + // + // ID - The concatenation of {"[", ID, "]"}, where ~ID~ is the return value of . + // + // Message - The message string, as determined by + // + // Terminator - If is '1', then the terminator string is {"-", SEV}, where ~SEV~ is + // the severity as determined by . If show_terminator is + // '0', then this is the empty string (""). + // + //For example, the following report messages... + //| `uvm_info("Example", "Info message", UVM_LOW) + //| uvm_report_info("Example", "No file/line"); + //| uvm_report_info("Example", "With context", UVM_LOW, + //| "demo_pkg.sv", 57, "example_context"); + //| + //| // show_verbosity = 1 + //| `uvm_info("Example", "With verbosity", UVM_LOW) + //| // show_terminator = 1 + //| `uvm_info("Example", "With terminator", UvM_LOW) + //| // show_verbosity = 1, show_terminator = 1 + //| `uvm_info("Example", "With both", UVM_NONE) + // + //...result in the output below + //| + //| UVM_INFO demo_pkg.sv(55) @ 0: uvm_test_top [Example] Info message + //| UVM_INFO @ 0: uvm_test_top [Example] No file/line + //| UVM_INFO demo_pkg.sv(57) @ 0: uvm_test_top@@example_context [Example] With context + //| + //| // show_verbosity = 1 + //| UVM_INFO(UVM_LOW) demo_pkg.sv(60) @ 0: uvm_test_top [Example] Info message + //| // show_terminator = 1 + //| UVM_INFO demo_pkg.sv(62) @ 0: uvm_test_top [Example] Info message -UVM_INFO + //| // show_verbosity = 1, show_terminator = 1 + //| UVM_INFO(UVM_NONE) demo_pkg.sv(64) @ 0: uvm_test_top [Example] With both -UVM_INFO + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + virtual function string compose_report_message(uvm_report_message report_message, + string report_object_name = ""); + + string sev_string; + uvm_severity l_severity; + uvm_verbosity l_verbosity; + string filename_line_string; + string time_str; + string line_str; + string context_str; + string verbosity_str; + string terminator_str; + string msg_body_str; + uvm_report_message_element_container el_container; + string prefix; + uvm_report_handler l_report_handler; + + l_severity = report_message.get_severity(); + sev_string = l_severity.name(); + + if (report_message.get_filename() != "") begin + line_str.itoa(report_message.get_line()); + filename_line_string = {report_message.get_filename(), "(", line_str, ") "}; + end + + // Make definable in terms of units. + $swrite(time_str, "%0t", $time); + + if (report_message.get_context() != "") + context_str = {"@@", report_message.get_context()}; + + if (show_verbosity) begin + if ($cast(l_verbosity, report_message.get_verbosity())) + verbosity_str = l_verbosity.name(); + else + verbosity_str.itoa(report_message.get_verbosity()); + verbosity_str = {"(", verbosity_str, ")"}; + end + + if (show_terminator) + terminator_str = {" -",sev_string}; + + el_container = report_message.get_element_container(); + if (el_container.size() == 0) + msg_body_str = report_message.get_message(); + else begin + uvm_printer uvm_default_printer = uvm_printer::get_default() ; + prefix = uvm_default_printer.get_line_prefix(); + uvm_default_printer.set_line_prefix(" +"); + msg_body_str = {report_message.get_message(), "\n", el_container.sprint()}; + uvm_default_printer.set_line_prefix(prefix); + end + + if (report_object_name == "") begin + l_report_handler = report_message.get_report_handler(); + report_object_name = l_report_handler.get_full_name(); + end + + compose_report_message = {sev_string, verbosity_str, " ", filename_line_string, "@ ", + time_str, ": ", report_object_name, context_str, + " [", report_message.get_id(), "] ", msg_body_str, terminator_str}; + + endfunction + + + // Function --NODOCS-- report_summarize + // + // Outputs statistical information on the reports issued by this central report + // server. This information will be sent to the command line if ~file~ is UVM_STDOUT, or + // to the file descriptor ~file~ if it is not UVM_STDOUT. + // + // The method in uvm_top calls this method. + + virtual function void report_summarize(UVM_FILE file = UVM_STDOUT); + string id; + string name; + string output_str; + string q[$]; + + uvm_report_catcher::summarize(); + q.push_back("\n--- UVM Report Summary ---\n\n"); + + if(m_max_quit_count != 0) begin + if ( m_quit_count >= m_max_quit_count ) + q.push_back("Quit count reached!\n"); + q.push_back($sformatf("Quit count : %5d of %5d\n",m_quit_count, m_max_quit_count)); + end + + q.push_back("** Report counts by severity\n"); + foreach(m_severity_count[s]) begin + q.push_back($sformatf("%s :%5d\n", s.name(), m_severity_count[s])); + end + + if (enable_report_id_count_summary) begin + q.push_back("** Report counts by id\n"); + foreach(m_id_count[id]) + q.push_back($sformatf("[%s] %5d\n", id, m_id_count[id])); + end + + `uvm_info("UVM/REPORT/SERVER",`UVM_STRING_QUEUE_STREAMING_PACK(q),UVM_NONE) + endfunction + +endclass + + +`endif // UVM_REPORT_SERVER_SVH diff --git a/test_regress/t/t_uvm/base/uvm_resource.svh b/test_regress/t/t_uvm/base/uvm_resource.svh new file mode 100644 index 0000000000..dd6c8aee0c --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_resource.svh @@ -0,0 +1,1424 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Paradigm Works +// Copyright 2010-2018 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Semifore +// Copyright 2017 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010-2011 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, Inc. +// Copyright 2011-2012 Cypress Semiconductor Corp. +// Copyright 2017-2018 Verific +// 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 - get_t +// +// Instances of get_t are stored in the history list as a record of each +// get. Failed gets are indicated with rsrc set to ~null~. This is part +// of the audit trail facility for resources. +//---------------------------------------------------------------------- +class get_t; + string name; + string scope; + uvm_resource_base rsrc; + time t; +endclass + +typedef class uvm_tree_printer ; + +// Title: Resources + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_resource_pool +// +// The global (singleton) resource database. +// +// Each resource is stored both by primary name and by type handle. The +// resource pool contains two associative arrays, one with name as the +// key and one with the type handle as the key. Each associative array +// contains a queue of resources. Each resource has a regular +// expression that represents the set of scopes over which it is visible. +// +//| +------+------------+ +------------+------+ +//| | name | rsrc queue | | rsrc queue | type | +//| +------+------------+ +------------+------+ +//| | | | | | | +//| +------+------------+ +-+-+ +------------+------+ +//| | | | | | |<--+---* | T | +//| +------+------------+ +-+-+ +-+-+ +------------+------+ +//| | A | *---+-->| | | | | | | +//| +------+------------+ +-+-+ | +------------+------+ +//| | | | | | | | | +//| +------+------------+ +-------+ +-+ +------------+------+ +//| | | | | | | | | +//| +------+------------+ | | +------------+------+ +//| | | | V V | | | +//| +------+------------+ +------+ +------------+------+ +//| | | | | rsrc | | | | +//| +------+------------+ +------+ +------------+------+ +// +// The above diagrams illustrates how a resource whose name is A and +// type is T is stored in the pool. The pool contains an entry in the +// type map for type T and an entry in the name map for name A. The +// queues in each of the arrays each contain an entry for the resource A +// whose type is T. The name map can contain in its queue other +// resources whose name is A which may or may not have the same type as +// our resource A. Similarly, the type map can contain in its queue +// other resources whose type is T and whose name may or may not be A. +// +// Resources are added to the pool by calling ; they are retrieved +// from the pool by calling or . When an object +// creates a new resource and calls the resource is made available to be +// retrieved by other objects outside of itself; an object gets a +// resource when it wants to access a resource not currently available +// in its scope. +// +// The scope is stored in the resource itself (not in the pool) so +// whether you get by name or by type the resource's visibility is +// the same. +// +// As an auditing capability, the pool contains a history of gets. A +// record of each get, whether by or , is stored +// in the audit record. Both successful and failed gets are recorded. At +// the end of simulation, or any time for that matter, you can dump the +// history list. This will tell which resources were successfully +// located and which were not. You can use this information +// to determine if there is some error in name, type, or +// scope that has caused a resource to not be located or to be incorrectly +// located (i.e. the wrong resource is located). +// +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto C.2.4.1 +class uvm_resource_pool; + + uvm_resource_types::rsrc_q_t rtab [string]; + uvm_resource_types::rsrc_q_t ttab [uvm_resource_base]; + + // struct for scope and precedence associated with each resource + typedef struct { + string scope ; + int unsigned precedence; + } rsrc_info_t ; + // table to set/get scope and precedence for resources + static rsrc_info_t ri_tab [uvm_resource_base]; + + get_t get_record [$]; // history of gets + + // @uvm-ieee 1800.2-2017 auto C.2.4.2.1 + function new(); + endfunction + + + // Function -- NODOCS -- get + // + // Returns the singleton handle to the resource pool + + // @uvm-ieee 1800.2-2017 auto C.2.4.2.2 + static function uvm_resource_pool get(); + uvm_resource_pool t_rp; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + t_rp = cs.get_resource_pool(); + return t_rp; + endfunction + + + // Function -- NODOCS -- spell_check + // + // Invokes the spell checker for a string s. The universe of + // correctly spelled strings -- i.e. the dictionary -- is the name + // map. + + function bit spell_check(string s); + return uvm_spell_chkr#(uvm_resource_types::rsrc_q_t)::check(rtab, s); + endfunction + + //----------- + // Group -- NODOCS -- Set + //----------- + + // Function -- NODOCS -- set + // + // Add a new resource to the resource pool. The resource is inserted + // into both the name map and type map so it can be located by + // either. + // + // An object creates a resources and ~sets~ it into the resource pool. + // Later, other objects that want to access the resource must ~get~ it + // from the pool + // + // Overrides can be specified using this interface. Either a name + // override, a type override or both can be specified. If an + // override is specified then the resource is entered at the front of + // the queue instead of at the back. It is not recommended that users + // specify the override parameter directly, rather they use the + // , , or + // functions. + // +`ifdef UVM_ENABLE_DEPRECATED_API + function void set (uvm_resource_base rsrc, + uvm_resource_types::override_t override = 0); + + // If resource handle is ~null~ then there is nothing to do. + if (rsrc == null) return ; + if (override) + set_override(rsrc, rsrc.get_scope()) ; + else + set_scope(rsrc, rsrc.get_scope()) ; + + endfunction +`endif //UVM_ENABLE_DEPRECATED_API + + // @uvm-ieee 1800.2-2017 auto C.2.4.3.1 + function void set_scope (uvm_resource_base rsrc, string scope); + + uvm_resource_types::rsrc_q_t rq; + string name; + uvm_resource_base type_handle; + uvm_resource_base r; + int unsigned i; + + // If resource handle is ~null~ then there is nothing to do. + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to set scope of a null resource"); + return; + end + + // Insert into the name map. Resources with empty names are + // anonymous resources and are not entered into the name map + name = rsrc.get_name(); + if ((name != "") && rtab.exists(name)) begin + rq = rtab[name]; + + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(r == rsrc) begin + ri_tab[rsrc].scope = uvm_glob_to_re(scope); + return ; + end + end + end + + if (rq == null) + rq = new(name); + + // Insert the resource into the queue associated with its name. + // Insert it with low priority (in the back of queue) . + rq.push_back(rsrc); + + rtab[name] = rq; + + // Insert into the type map + type_handle = rsrc.get_type_handle(); + if(ttab.exists(type_handle)) + rq = ttab[type_handle]; + else + rq = new(); + + // Insert the resource into the queue associated with its type. + // Insert it with low priority (in the back of queue) . + rq.push_back(rsrc); + ttab[type_handle] = rq; + + // Set the scope of resource. + ri_tab[rsrc].scope = uvm_glob_to_re(scope); + ri_tab[rsrc].precedence = get_default_precedence(); + + endfunction + + + // Function -- NODOCS -- set_override + // + // The resource provided as an argument will be entered into the pool + // and will override both by name and type. + // Default value to 'scope' argument is violating 1800.2-2017 LRM, but it + // is added to make the routine backward compatible + + // @uvm-ieee 1800.2-2017 auto C.2.4.3.2 + function void set_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; +`ifdef UVM_ENABLE_DEPRECATED_API + if ((scope == "") && (rsrc != null)) s = rsrc.get_scope(); +`endif //UVM_ENABLE_DEPRECATED_API + set_scope(rsrc, s); + set_priority(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + + + // Function -- NODOCS -- set_name_override + // + // The resource provided as an argument will entered into the pool + // using normal precedence in the type map and will override the name. + // Default value to 'scope' argument is violating 1800.2-2017 LRM, but it + // is added to make the routine backward compatible + + // @uvm-ieee 1800.2-2017 auto C.2.4.3.3 + function void set_name_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; +`ifdef UVM_ENABLE_DEPRECATED_API + if ((scope == "") && (rsrc != null)) s = rsrc.get_scope(); +`endif //UVM_ENABLE_DEPRECATED_API + set_scope(rsrc, s); + set_priority_name(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + + + // Function -- NODOCS -- set_type_override + // + // The resource provided as an argument will be entered into the pool + // using normal precedence in the name map and will override the type. + // Default value to 'scope' argument is violating 1800.2-2017 LRM, but it + // is added to make the routine backward compatible + + // @uvm-ieee 1800.2-2017 auto C.2.4.3.4 + function void set_type_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; +`ifdef UVM_ENABLE_DEPRECATED_API + if ((scope == "") && (rsrc != null)) s = rsrc.get_scope(); +`endif //UVM_ENABLE_DEPRECATED_API + set_scope(rsrc, s); + set_priority_type(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.2.4.3.5 + virtual function bit get_scope(uvm_resource_base rsrc, + output string scope); + + uvm_resource_types::rsrc_q_t rq; + string name; + uvm_resource_base r; + int unsigned i; + + // If resource handle is ~null~ then there is nothing to do. + if(rsrc == null) + return 0; + + // Search the resouce in the name map. Resources with empty names are + // anonymous resources and are not entered into the name map + name = rsrc.get_name(); + if((name != "") && rtab.exists(name)) begin + rq = rtab[name]; + + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(r == rsrc) begin + // Resource is in pool, set the scope + scope = ri_tab[rsrc].scope; + return 1; + end + end + end + + // Resource is not in pool + scope = ""; + return 0; + + endfunction + + // Function -- NODOCS -- delete + // + // If rsrc exists within the pool, then it is removed from all internal maps. If the rsrc is null, or does not exist + // within the pool, then the request is silently ignored. + + + // @uvm-ieee 1800.2-2017 auto C.2.4.3.6 + virtual function void delete ( uvm_resource_base rsrc ); + string name; + uvm_resource_base type_handle; + + if (rsrc != null) begin + name = rsrc.get_name(); + if(name != "") begin + if(rtab.exists(name)) + rtab.delete(name); + end + + type_handle = rsrc.get_type_handle(); + if(ttab.exists(type_handle)) begin + int q_size = ttab[type_handle].size(); + + if (q_size == 1) + ttab.delete(type_handle); + else begin + int i; + for (i=0; i and locate the set of resources that + // matches the name or type (respectively) and is visible in the + // current scope. These functions return a queue of resources. + // + // traverse a queue of resources and + // returns the one with the highest precedence -- i.e. the one whose + // precedence member has the highest value. + // + // and use and + // (respectively) and to find the resource with + // the highest priority that matches the other search criteria. + + + // Function -- NODOCS -- lookup_name + // + // Lookup resources by ~name~. Returns a queue of resources that + // match the ~name~, ~scope~, and ~type_handle~. If no resources + // match the queue is returned empty. If ~rpterr~ is set then a + // warning is issued if no matches are found, and the spell checker is + // invoked on ~name~. If ~type_handle~ is ~null~ then a type check is + // not made and resources are returned that match only ~name~ and + // ~scope~. + + // @uvm-ieee 1800.2-2017 auto C.2.4.4.1 + function uvm_resource_types::rsrc_q_t lookup_name(string scope = "", + string name, + uvm_resource_base type_handle = null, + bit rpterr = 1); + uvm_resource_types::rsrc_q_t rq; + uvm_resource_types::rsrc_q_t q; + uvm_resource_base rsrc; + uvm_resource_base r; + string rsrcs; + + // ensure rand stability during lookup + begin + process p = process::self(); + string s; + if(p!=null) s=p.get_randstate(); + q=new(); + if(p!=null) p.set_randstate(s); + end + + + // resources with empty names are anonymous and do not exist in the name map + if(name == "") + return q; + + // Does an entry in the name map exist with the specified name? + // If not, then we're done + if(!rtab.exists(name)) begin + if(rpterr) void'(spell_check(name)); + return q; + end + + rsrc = null; + rq = rtab[name]; + for(int i=0; i prec) begin + rsrc = r; + prec = c_prec; + end + end + + return rsrc; + + endfunction + + // Function -- NODOCS -- sort_by_precedence + // + // Given a list of resources, obtained for example from , + // sort the resources in precedence order. The highest precedence + // resource will be first in the list and the lowest precedence will + // be last. Resources that have the same precedence and the same name + // will be ordered by most recently set first. + + // @uvm-ieee 1800.2-2017 auto C.2.4.4.3 + static function void sort_by_precedence(ref uvm_resource_types::rsrc_q_t q); + uvm_resource_types::rsrc_q_t all[int]; + uvm_resource_base r; + int unsigned prec; + + for(int i=0; i", scope, null); + return null; + end + + rsrc = q.get(0); + push_get_record("", scope, rsrc); + return rsrc; + + endfunction + + // Function -- NODOCS -- lookup_regex_names + // + // This utility function answers the question, for a given ~name~, + // ~scope~, and ~type_handle~, what are all of the resources with requested name, + // a matching scope (where the resource scope may be a + // regular expression), and a matching type? + // ~name~ and ~scope~ are explicit values. + + function uvm_resource_types::rsrc_q_t lookup_regex_names(string scope, + string name, + uvm_resource_base type_handle = null); + return lookup_name(scope, name, type_handle, 0); + endfunction + + // Function -- NODOCS -- lookup_regex + // + // Looks for all the resources whose name matches the regular + // expression argument and whose scope matches the current scope. + + // @uvm-ieee 1800.2-2017 auto C.2.4.4.7 + function uvm_resource_types::rsrc_q_t lookup_regex(string re, scope); + + uvm_resource_types::rsrc_q_t rq; + uvm_resource_types::rsrc_q_t result_q; + int unsigned i; + uvm_resource_base r; + string s; + + result_q = new(); + + foreach (rtab[name]) begin + if ( ! uvm_is_match(re, name) ) + continue; + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(ri_tab.exists(r) && uvm_is_match(ri_tab[r].scope, scope)) + result_q.push_back(r); + end + end + + return result_q; + + endfunction + + // Function -- NODOCS -- lookup_scope + // + // This is a utility function that answers the question: For a given + // ~scope~, what resources are visible to it? Locate all the resources + // that are visible to a particular scope. This operation could be + // quite expensive, as it has to traverse all of the resources in the + // database. + + // @uvm-ieee 1800.2-2017 auto C.2.4.4.8 + function uvm_resource_types::rsrc_q_t lookup_scope(string scope); + + uvm_resource_types::rsrc_q_t rq; + uvm_resource_base r; + int unsigned i; + + int unsigned err; + uvm_resource_types::rsrc_q_t q = new(); + + //iterate in reverse order for the special case of autoconfig + //of arrays. The array name with no [] needs to be higher priority. + //This has no effect an manual accesses. + string name; + + if(rtab.last(name)) begin + do begin + rq = rtab[name]; + for(int i = 0; i < rq.size(); ++i) begin + r = rq.get(i); + if(ri_tab.exists(r) && uvm_is_match(ri_tab[r].scope, scope)) begin + q.push_back(r); + end + end + end while(rtab.prev(name)); + end + + return q; + + endfunction + + //-------------------- + // Group -- NODOCS -- Set Priority + //-------------------- + // + // Functions for altering the search priority of resources. Resources + // are stored in queues in the type and name maps. When retrieving + // resources, either by type or by name, the resource queue is search + // from front to back. The first one that matches the search criteria + // is the one that is returned. The ~set_priority~ functions let you + // change the order in which resources are searched. For any + // particular resource, you can set its priority to UVM_HIGH, in which + // case the resource is moved to the front of the queue, or to UVM_LOW in + // which case the resource is moved to the back of the queue. + + // function- set_priority_queue + // + // This function handles the mechanics of moving a resource to either + // the front or back of the queue. + + local function void set_priority_queue(uvm_resource_base rsrc, + ref uvm_resource_types::rsrc_q_t q, + uvm_resource_types::priority_e pri); + + uvm_resource_base r; + int unsigned i; + + string msg; + string name = rsrc.get_name(); + + for(i = 0; i < q.size(); i++) begin + r = q.get(i); + if(r == rsrc) break; + end + + if(r != rsrc) begin + $sformat(msg, "Handle for resource named %s is not in the name name; cannot change its priority", name); + uvm_report_error("NORSRC", msg); + return; + end + + q.delete(i); + + case(pri) + uvm_resource_types::PRI_HIGH: q.push_front(rsrc); + uvm_resource_types::PRI_LOW: q.push_back(rsrc); + endcase + + endfunction + + + // Function -- NODOCS -- set_priority_type + // + // Change the priority of the ~rsrc~ based on the value of ~pri~, the + // priority enum argument. This function changes the priority only in + // the type map, leaving the name map untouched. + + // @uvm-ieee 1800.2-2017 auto C.2.4.5.1 + function void set_priority_type(uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + + uvm_resource_base type_handle; + string msg; + uvm_resource_types::rsrc_q_t q; + + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to change the serach priority of a null resource"); + return; + end + + type_handle = rsrc.get_type_handle(); + if(!ttab.exists(type_handle)) begin + $sformat(msg, "Type handle for resrouce named %s not found in type map; cannot change its search priority", rsrc.get_name()); + uvm_report_error("RNFTYPE", msg); + return; + end + + q = ttab[type_handle]; + set_priority_queue(rsrc, q, pri); + endfunction + + + // Function -- NODOCS -- set_priority_name + // + // Change the priority of the ~rsrc~ based on the value of ~pri~, the + // priority enum argument. This function changes the priority only in + // the name map, leaving the type map untouched. + + // @uvm-ieee 1800.2-2017 auto C.2.4.5.2 + function void set_priority_name(uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + + string name; + string msg; + uvm_resource_types::rsrc_q_t q; + + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to change the serach priority of a null resource"); + return; + end + + name = rsrc.get_name(); + if(!rtab.exists(name)) begin + $sformat(msg, "Resrouce named %s not found in name map; cannot change its search priority", name); + uvm_report_error("RNFNAME", msg); + return; + end + + q = rtab[name]; + set_priority_queue(rsrc, q, pri); + + endfunction + + + // Function -- NODOCS -- set_priority + // + // Change the search priority of the ~rsrc~ based on the value of ~pri~, + // the priority enum argument. This function changes the priority in + // both the name and type maps. + + // @uvm-ieee 1800.2-2017 auto C.2.4.5.3 + function void set_priority (uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + set_priority_type(rsrc, pri); + set_priority_name(rsrc, pri); + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.2.4.5.4 + static function void set_default_precedence( int unsigned precedence); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + cs.set_resource_pool_default_precedence(precedence); + endfunction + + + static function int unsigned get_default_precedence(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_resource_pool_default_precedence(); + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.2.4.5.6 + virtual function void set_precedence(uvm_resource_base r, + int unsigned p=uvm_resource_pool::get_default_precedence()); + + uvm_resource_types::rsrc_q_t q; + string name; + int unsigned i; + uvm_resource_base rsrc; + + if(r == null) begin + uvm_report_warning("NULLRASRC", "attempting to set precedence of a null resource"); + return; + end + + name = r.get_name(); + if(rtab.exists(name)) begin + q = rtab[name]; + + for(i = 0; i < q.size(); i++) begin + rsrc = q.get(i); + if(rsrc == r) break; + end + end + + if(r != rsrc) begin + uvm_report_warning("NORSRC", $sformatf("resource named %s is not placed within the pool", name)); + return; + end + + ri_tab[r].precedence = p; + + endfunction + + + virtual function int unsigned get_precedence(uvm_resource_base r); + + uvm_resource_types::rsrc_q_t q; + string name; + int unsigned i; + uvm_resource_base rsrc; + + if(r == null) begin + uvm_report_warning("NULLRASRC", "attempting to get precedence of a null resource"); + return uvm_resource_pool::get_default_precedence(); + end + + name = r.get_name(); + if(rtab.exists(name)) begin + q = rtab[name]; + + for(i = 0; i < q.size(); i++) begin + rsrc = q.get(i); + if(rsrc == r) break; + end + end + + if(r != rsrc) begin + uvm_report_warning("NORSRC", $sformatf("resource named %s is not placed within the pool", name)); + return uvm_resource_pool::get_default_precedence(); + end + + return ri_tab[r].precedence; + + endfunction + + + //-------------------------------------------------------------------- + // Group -- NODOCS -- Debug + //-------------------------------------------------------------------- + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- find_unused_resources + // + // Locate all the resources that have at least one write and no reads + + function uvm_resource_types::rsrc_q_t find_unused_resources(); + + uvm_resource_types::rsrc_q_t rq; + uvm_resource_types::rsrc_q_t q = new; + int unsigned i; + uvm_resource_base r; + uvm_resource_types::access_t a; + int reads; + int writes; + + foreach (rtab[name]) begin + rq = rtab[name]; + for(int i=0; i 0 && reads == 0) + q.push_back(r); + end + end + + return q; + + endfunction +`endif // UVM_ENABLE_DEPRECATED_API + + // Prints resouce queue into ~printer~, non-LRM + function void m_print_resources(uvm_printer printer, + uvm_resource_types::rsrc_q_t rq, + bit audit = 0); + + printer.push_element(rq.get_name(), + "uvm_queue#(uvm_resource_base)", + $sformatf("%0d",rq.size()), + uvm_object_value_str(rq)); + + for(int i=0; i"); + else + m_print_resources(printer, rq, audit); + `uvm_info("UVM/RESOURCE_POOL/PRINT_QUEUE", + printer.emit(), + UVM_NONE) + endfunction + + + // Function -- NODOCS -- dump + // + // dump the entire resource pool. The resource pool is traversed and + // each resource is printed. The utility function print_resources() + // is used to initiate the printing. If the ~audit~ bit is set then + // the audit trail is dumped for each resource. + + function void dump(bit audit = 0, uvm_printer printer = null); + + string name; + static uvm_tree_printer m_printer; + + if (m_printer == null) begin + m_printer = new(); + m_printer.set_type_name_enabled(1); + end + + + if (printer == null) + printer = m_printer; + + printer.flush(); + printer.push_element("uvm_resource_pool", + "", + $sformatf("%0d",rtab.size()), + ""); + + foreach (rtab[name]) begin + m_print_resources(printer, rtab[name], audit); + end + + printer.pop_element(); + + `uvm_info("UVM/RESOURCE/DUMP", printer.emit(), UVM_NONE) + + endfunction + +endclass + +//---------------------------------------------------------------------- +// Class: uvm_resource #(T) +// Implementation of uvm_resource#(T) as defined in section C.2.5.1 of +// 1800.2-2017. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto C.2.5.1 +class uvm_resource #(type T=int) extends uvm_resource_base; + + typedef uvm_resource#(T) this_type; + + // singleton handle that represents the type of this resource + static this_type my_type = get_type(); + + // Can't be rand since things like rand strings are not legal. + protected T val; + + // Because of uvm_resource#(T)::get_type, we can't use + // the macros. We need to do it all manually. + typedef uvm_object_registry#(this_type) type_id; + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction : get_object_type + virtual function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction : create + `uvm_type_name_decl($sformatf("uvm_resource#(%s)", `uvm_typename(T))) + + +`ifdef UVM_ENABLE_DEPRECATED_API + function new(string name="", scope=""); + super.new(name, scope); + endfunction +`else + // @uvm-ieee 1800.2-2017 auto C.2.5.2 + function new(string name=""); + super.new(name); + endfunction +`endif // UVM_ENABLE_DEPRECATED_API + + virtual function string m_value_type_name(); + return `uvm_typename(T); + endfunction : m_value_type_name + + virtual function string m_value_as_string(); + return $sformatf("%0p", val); + endfunction : m_value_as_string + + //---------------------- + // Group -- NODOCS -- Type Interface + //---------------------- + // + // Resources can be identified by type using a static type handle. + // The parent class provides the virtual function interface + // . Here we implement it by returning the static type + // handle. + + // Function -- NODOCS -- get_type + // + // Static function that returns the static type handle. The return + // type is this_type, which is the type of the parameterized class. + + static function this_type get_type(); + if(my_type == null) + my_type = new(); + return my_type; + endfunction + + // Function -- NODOCS -- get_type_handle + // + // Returns the static type handle of this resource in a polymorphic + // fashion. The return type of get_type_handle() is + // uvm_resource_base. This function is not static and therefore can + // only be used by instances of a parameterized resource. + + // @uvm-ieee 1800.2-2017 auto C.2.5.3.2 + function uvm_resource_base get_type_handle(); + return get_type(); + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + //------------------------- + // Group -- NODOCS -- Set/Get Interface + //------------------------- + // + // uvm_resource#(T) provides an interface for setting and getting a + // resources. Specifically, a resource can insert itself into the + // resource pool. It doesn't make sense for a resource to get itself, + // since you can't call a function on a handle you don't have. + // However, a static get interface is provided as a convenience. This + // obviates the need for the user to get a handle to the global + // resource pool as this is done for him here. + + // Function -- NODOCS -- set + // + // Simply put this resource into the global resource pool + + function void set(); + uvm_resource_pool rp = uvm_resource_pool::get(); + rp.set_scope(this, get_scope()); + endfunction + + + // Function -- NODOCS -- set_override + // + // Put a resource into the global resource pool as an override. This + // means it gets put at the head of the list and is searched before + // other existing resources that occupy the same position in the name + // map or the type map. The default is to override both the name and + // type maps. However, using the ~override~ argument you can specify + // that either the name map or type map is overridden. + + function void set_override(uvm_resource_types::override_t override = 2'b11); + uvm_resource_pool rp = uvm_resource_pool::get(); + if(override) + rp.set_override(this, get_scope()); + else + rp.set_scope(this, get_scope()); + endfunction + + // Function -- NODOCS -- get_by_name + // + // looks up a resource by ~name~ in the name map. The first resource + // with the specified name, whose type is the current type, and is + // visible in the specified ~scope~ is returned, if one exists. The + // ~rpterr~ flag indicates whether or not an error should be reported + // if the search fails. If ~rpterr~ is set to one then a failure + // message is issued, including suggested spelling alternatives, based + // on resource names that exist in the database, gathered by the spell + // checker. + + static function this_type get_by_name(string scope, + string name, + bit rpterr = 1); + + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + this_type rsrc; + string msg; + + rsrc_base = rp.get_by_name(scope, name, my_type, rpterr); + if(rsrc_base == null) + return null; + + if(!$cast(rsrc, rsrc_base)) begin + if(rpterr) begin + $sformat(msg, "Resource with name %s in scope %s has incorrect type", name, scope); + `uvm_warning("RSRCTYPE", msg) + end + return null; + end + + return rsrc; + + endfunction + + // Function -- NODOCS -- get_by_type + // + // looks up a resource by ~type_handle~ in the type map. The first resource + // with the specified ~type_handle~ that is visible in the specified ~scope~ is + // returned, if one exists. If there is no resource matching the specifications, + // ~null~ is returned. + + static function this_type get_by_type(string scope = "", + uvm_resource_base type_handle); + + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + this_type rsrc; + string msg; + + if(type_handle == null) + return null; + + rsrc_base = rp.get_by_type(scope, type_handle); + if(rsrc_base == null) + return null; + + if(!$cast(rsrc, rsrc_base)) begin + $sformat(msg, "Resource with specified type handle in scope %s was not located", scope); + `uvm_warning("RSRCNF", msg) + return null; + end + + return rsrc; + + endfunction +`endif // UVM_ENABLE_DEPRECATED_API + + //---------------------------- + // Group -- NODOCS -- Read/Write Interface + //---------------------------- + // + // and provide a type-safe interface for getting and + // setting the object in the resource container. The interface is + // type safe because the value argument for and the return + // value of are T, the type supplied in the class parameter. + // If either of these functions is used in an incorrect type context + // the compiler will complain. + + // Function: read + // + //| function T read(uvm_object accessor = null); + // + // This function is the implementation of the uvm_resource#(T)::read + // method detailed in IEEE1800.2-2017 section C.2.5.4.1 + // + // It calls uvm_resource_base::record_read_access before returning the value. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + // @uvm-ieee 1800.2-2017 auto C.2.5.4.1 + function T read(uvm_object accessor = null); + record_read_access(accessor); + return val; + endfunction + + // Function: write + // + //| function void write(T t, uvm_object accessor = null); + // + // This function is the implementation of the uvm_resource#(T)::write + // method detailed in IEEE1800.2-2017 section C.2.5.4.2 + // + // It calls uvm_resource_base::record_write_access before writing the value. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + // @uvm-ieee 1800.2-2017 auto C.2.5.4.2 + function void write(T t, uvm_object accessor = null); + + if(is_read_only()) begin + uvm_report_error("resource", $sformatf("resource %s is read only -- cannot modify", get_name())); + return; + end + + // Set the modified bit and record the transaction only if the value + // has actually changed. + if(val == t) + return; + + record_write_access(accessor); + + // set the value and set the dirty bit + val = t; + modified = 1; + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + //---------------- + // Group -- NODOCS -- Priority + //---------------- + // + // Functions for manipulating the search priority of resources. These + // implementations of the interface defined in the base class delegate + // to the resource pool. + + + // Function -- NODOCS -- set priority + // + // Change the search priority of the resource based on the value of + // the priority enum argument, ~pri~. + + function void set_priority (uvm_resource_types::priority_e pri); + uvm_resource_pool rp = uvm_resource_pool::get(); + rp.set_priority(this, pri); + endfunction + +`endif // UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- get_highest_precedence + // + // In a queue of resources, locate the first one with the highest + // precedence whose type is T. This function is static so that it can + // be called from anywhere. + + static function this_type get_highest_precedence(ref uvm_resource_types::rsrc_q_t q); + + this_type rsrc; + this_type r; + uvm_resource_types::rsrc_q_t tq; + uvm_resource_base rb; + uvm_resource_pool rp = uvm_resource_pool::get(); + + if(q.size() == 0) + return null; + + tq = new(); + rsrc = null; + + for(int i = 0; i < q.size(); ++i) begin + if($cast(r, q.get(i))) begin + tq.push_back(r) ; + end + end + + rb = rp.get_highest_precedence(tq); + if (!$cast(rsrc, rb)) + return null; + + return rsrc; + + endfunction + +endclass + diff --git a/test_regress/t/t_uvm/base/uvm_resource_base.svh b/test_regress/t/t_uvm/base/uvm_resource_base.svh new file mode 100644 index 0000000000..b1abecb56f --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_resource_base.svh @@ -0,0 +1,550 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, Inc. +// Copyright 2017-2018 Verific +// 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- Resources +// +// Topic: Intro +// +// A resource is a parameterized container that holds arbitrary data. +// Resources can be used to configure components, supply data to +// sequences, or enable sharing of information across disparate parts of +// a testbench. They are stored using scoping information so their +// visibility can be constrained to certain parts of the testbench. +// Resource containers can hold any type of data, constrained only by +// the data types available in SystemVerilog. Resources can contain +// scalar objects, class handles, queues, lists, or even virtual +// interfaces. +// +// Resources are stored in a resource database so that each resource can +// be retrieved by name or by type. The database has both a name table +// and a type table and each resource is entered into both. The database +// is globally accessible. +// +// Each resource has a set of scopes over which it is visible. The set +// of scopes is represented as a regular expression. When a resource is +// looked up the scope of the entity doing the looking up is supplied to +// the lookup function. This is called the ~current scope~. If the +// current scope is in the set of scopes over which a resource is +// visible then the resource can be retuned in the lookup. +// +// Resources can be looked up by name or by type. To support type lookup +// each resource has a static type handle that uniquely identifies the +// type of each specialized resource container. +// +// Multiple resources that have the same name are stored in a queue. +// Each resource is pushed into a queue with the first one at the front +// of the queue and each subsequent one behind it. The same happens for +// multiple resources that have the same type. The resource queues are +// searched front to back, so those placed earlier in the queue have +// precedence over those placed later. +// +// The precedence of resources with the same name or same type can be +// altered. One way is to set the ~precedence~ member of the resource +// container to any arbitrary value. The search algorithm will return +// the resource with the highest precedence. In the case where there +// are multiple resources that match the search criteria and have the +// same (highest) precedence, the earliest one located in the queue will +// be one returned. Another way to change the precedence is to use the +// set_priority function to move a resource to either the front or back +// of the queue. +// +// The classes defined here form the low level layer of the resource +// database. The classes include the resource container and the database +// that holds the containers. The following set of classes are defined +// here: +// +// : A class without methods or members, only +// typedefs and enums. These types and enums are used throughout the +// resources facility. Putting the types in a class keeps them confined +// to a specific name space. +// +// : policy class for setting options, such +// as auditing, which effect resources. +// +// : the base (untyped) resource class living in the +// resource database. This class includes the interface for setting a +// resource as read-only, notification, scope management, altering +// search priority, and managing auditing. +// +// : parameterized resource container. This class +// includes the interfaces for reading and writing each resource. +// Because the class is parameterized, all the access functions are type +// safe. +// +// : the resource database. This is a singleton +// class object. +//---------------------------------------------------------------------- + +typedef class uvm_resource_base; // forward reference + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_resource_types +// +// Provides typedefs and enums used throughout the resources facility. +// This class has no members or methods, only typedefs. It's used in +// lieu of package-scope types. When needed, other classes can use +// these types by prefixing their usage with uvm_resource_types::. E.g. +// +//| uvm_resource_types::rsrc_q_t queue; +// +//---------------------------------------------------------------------- +class uvm_resource_types; + + // types uses for setting overrides + typedef bit[1:0] override_t; + typedef enum override_t { TYPE_OVERRIDE = 2'b01, + NAME_OVERRIDE = 2'b10 } override_e; + + // general purpose queue of resourcex + typedef uvm_queue#(uvm_resource_base) rsrc_q_t; + + // enum for setting resource search priority + typedef enum { PRI_HIGH, PRI_LOW } priority_e; + + // access record for resources. A set of these is stored for each + // resource by accessing object. It's updated for each read/write. + typedef struct + { + time read_time; + time write_time; + int unsigned read_count; + int unsigned write_count; + } access_t; + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_resource_options +// +// Provides a namespace for managing options for the +// resources facility. The only thing allowed in this class is static +// local data members and static functions for manipulating and +// retrieving the value of the data members. The static local data +// members represent options and settings that control the behavior of +// the resources facility. + +// Options include: +// +// * auditing: on/off +// +// The default for auditing is on. You may wish to turn it off to +// for performance reasons. With auditing off memory is not +// consumed for storage of auditing information and time is not +// spent collecting and storing auditing information. Of course, +// during the period when auditing is off no audit trail information +// is available +// +//---------------------------------------------------------------------- +class uvm_resource_options; + + static local bit auditing = 1; + + // Function -- NODOCS -- turn_on_auditing + // + // Turn auditing on for the resource database. This causes all + // reads and writes to the database to store information about + // the accesses. Auditing is turned on by default. + + static function void turn_on_auditing(); + auditing = 1; + endfunction + + // Function -- NODOCS -- turn_off_auditing + // + // Turn auditing off for the resource database. If auditing is turned off, + // it is not possible to get extra information about resource + // database accesses. + + static function void turn_off_auditing(); + auditing = 0; + endfunction + + // Function -- NODOCS -- is_auditing + // + // Returns 1 if the auditing facility is on and 0 if it is off. + + static function bit is_auditing(); + return auditing; + endfunction +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_resource_base +// +// Non-parameterized base class for resources. Supports interfaces for +// scope matching, and virtual functions for printing the resource and +// for printing the accessor list +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Class: uvm_resource_base +// +// The library implements the following public API beyond what is +// documented in 1800.2. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto C.2.3.1 +virtual class uvm_resource_base extends uvm_object; + +`ifdef UVM_ENABLE_DEPRECATED_API + protected string scope; +`endif // UVM_ENABLE_DEPRECATED_API + protected bit modified; + protected bit read_only; + + uvm_resource_types::access_t access[string]; + +`ifdef UVM_ENABLE_DEPRECATED_API + // variable -- NODOCS -- precedence + // + // This variable is used to associate a precedence that a resource + // has with respect to other resources which match the same scope + // and name. Resources are set to the initially, + // and may be set to a higher or lower precedence as desired. + + int unsigned precedence; + + // variable -- NODOCS -- default_precedence + // + // The default precedence for an resource that has been created. + // When two resources have the same precedence, the first resource + // found has precedence. + // + + static int unsigned default_precedence = 1000; +`endif // UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- new + // + // constructor for uvm_resource_base. The constructor takes two + // arguments, the name of the resource and a regular expression which + // represents the set of scopes over which this resource is visible. + +`ifdef UVM_ENABLE_DEPRECATED_API + function new(string name = "", string s = "*"); + super.new(name); + set_scope(s); + modified = 0; + read_only = 0; + precedence = default_precedence; + endfunction +`else + // @uvm-ieee 1800.2-2017 auto C.2.3.2.1 + function new(string name = ""); + super.new(name); + modified = 0; + read_only = 0; + endfunction +`endif // UVM_ENABLE_DEPRECATED_API + + + // Function -- NODOCS -- get_type_handle + // + // Pure virtual function that returns the type handle of the resource + // container. + + // @uvm-ieee 1800.2-2017 auto C.2.3.2.2 + pure virtual function uvm_resource_base get_type_handle(); + + + //--------------------------- + // Group -- NODOCS -- Read-only Interface + //--------------------------- + + // Function -- NODOCS -- set_read_only + // + // Establishes this resource as a read-only resource. An attempt + // to call on the resource will cause an error. + + // @uvm-ieee 1800.2-2017 auto C.2.3.3.1 + function void set_read_only(); + read_only = 1; + endfunction + + // function set_read_write + // + // Returns the resource to normal read-write capability. + + // Implementation question: Not sure if this function is necessary. + // Once a resource is set to read_only no one should be able to change + // that. If anyone can flip the read_only bit then the resource is not + // truly read_only. + + function void set_read_write(); + read_only = 0; + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.2.3.3.2 + function bit is_read_only(); + return read_only; + endfunction + + + //-------------------- + // Group -- NODOCS -- Notification + //-------------------- + + // Task -- NODOCS -- wait_modified + // + // This task blocks until the resource has been modified -- that is, a + // operation has been performed. When a + // is performed the modified bit is set which + // releases the block. Wait_modified() then clears the modified bit so + // it can be called repeatedly. + + // @uvm-ieee 1800.2-2017 auto C.2.3.4 + task wait_modified(); + wait (modified == 1); + modified = 0; + endtask + +`ifdef UVM_ENABLE_DEPRECATED_API + //----------------------- + // Group -- NODOCS -- Scope Interface + //----------------------- + // + + // Function -- NODOCS -- set_scope + // + // Set the value of the regular expression that identifies the set of + // scopes over which this resource is visible. If the supplied + // argument is a glob it will be converted to a regular expression + // before it is stored. + // + function void set_scope(string s); + scope = uvm_glob_to_re(s); + endfunction + + // Function -- NODOCS -- get_scope + // + // Retrieve the regular expression string that identifies the set of + // scopes over which this resource is visible. + // + function string get_scope(); + return scope; + endfunction + + // Function -- NODOCS -- match_scope + // + // Using the regular expression facility, determine if this resource + // is visible in a scope. Return one if it is, zero otherwise. + // + function bit match_scope(string s); + int match = uvm_is_match(scope, s); + return match; + endfunction + + //---------------- + // Group -- NODOCS -- Priority + //---------------- + // + // Functions for manipulating the search priority of resources. The + // function definitions here are pure virtual and are implemented in + // derived classes. The definitons serve as a priority management + // interface. + + // Function -- NODOCS -- set priority + // + // Change the search priority of the resource based on the value of + // the priority enum argument. + // + pure virtual function void set_priority (uvm_resource_types::priority_e pri); +`endif // UVM_ENABLE_DEPRECATED_API + + //------------------------- + // Group -- NODOCS -- Utility Functions + //------------------------- + + // function convert2string + // + // Create a string representation of the resource value. By default + // we don't know how to do this so we just return a "?". Resource + // specializations are expected to override this function to produce a + // proper string representation of the resource value. + + function string convert2string(); + return $sformatf("(%s) %s", m_value_type_name(), m_value_as_string()); + endfunction // convert2string + + // Helper for printing externally, non-LRM + pure virtual function string m_value_type_name(); + pure virtual function string m_value_as_string(); + + function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_generic_element("val", m_value_type_name(), "", m_value_as_string()); + endfunction : do_print + + + //------------------- + // Group: Audit Trail + //------------------- + // + // To find out what is happening as the simulation proceeds, an audit + // trail of each read and write is kept. The and + // methods each take an accessor argument. This is a + // handle to the object that performed that resource access. + // + //| function T read(uvm_object accessor = null); + //| function void write(T t, uvm_object accessor = null); + // + // The accessor can by anything as long as it is derived from + // uvm_object. The accessor object can be a component or a sequence + // or whatever object from which a read or write was invoked. + // Typically the ~this~ handle is used as the + // accessor. For example: + // + //| uvm_resource#(int) rint; + //| int i; + //| ... + //| rint.write(7, this); + //| i = rint.read(this); + // + // The accessor's ~get_full_name()~ is stored as part of the audit trail. + // This way you can find out what object performed each resource access. + // Each audit record also includes the time of the access (simulation time) + // and the particular operation performed (read or write). + // + // Auditing is controlled through the class. + + // Function: record_read_access + // + // Record the read access information for this resource for debug purposes. + // This information is used by function. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + function void record_read_access(uvm_object accessor = null); + + string str; + uvm_resource_types::access_t access_record; + + // If an accessor object is supplied then get the accessor record. + // Otherwise create a new access record. In either case populate + // the access record with information about this access. Check + // first to make sure that auditing is turned on. + + if(!uvm_resource_options::is_auditing()) + return; + + // If an accessor is supplied, then use its name + // as the database entry for the accessor record. + // Otherwise, use "" as the database entry. + if(accessor != null) + str = accessor.get_full_name(); + else + str = ""; + + // Create a new accessor record if one does not exist + if(access.exists(str)) + access_record = access[str]; + else + init_access_record(access_record); + + // Update the accessor record + access_record.read_count++; + access_record.read_time = $realtime; + access[str] = access_record; + + endfunction + + // Function: record_write_access + // + // Record the write access information for this resource for debug purposes. + // This information is used by function. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + function void record_write_access(uvm_object accessor = null); + + string str; + + // If an accessor object is supplied then get the accessor record. + // Otherwise create a new access record. In either case populate + // the access record with information about this access. Check + // first that auditing is turned on + + if(uvm_resource_options::is_auditing()) begin + if(accessor != null) begin + uvm_resource_types::access_t access_record; + string str; + str = accessor.get_full_name(); + if(access.exists(str)) + access_record = access[str]; + else + init_access_record(access_record); + access_record.write_count++; + access_record.write_time = $realtime; + access[str] = access_record; + end + end + endfunction + + // Function: print_accessors + // + // Print the read/write access history of the resource, using the accessor + // argument which is passed to the + // and + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + virtual function void print_accessors(); + + string str; + uvm_component comp; + uvm_resource_types::access_t access_record; + string qs[$]; + + if(access.num() == 0) + return; + + foreach (access[i]) begin + str = i; + access_record = access[str]; + qs.push_back($sformatf("%s reads: %0d @ %0t writes: %0d @ %0t\n",str, + access_record.read_count, + access_record.read_time, + access_record.write_count, + access_record.write_time)); + end + `uvm_info("UVM/RESOURCE/ACCESSOR",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE) + + endfunction + + + // Function -- NODOCS -- init_access_record + // + // Initialize a new access record + // + function void init_access_record (inout uvm_resource_types::access_t access_record); + access_record.read_time = 0; + access_record.write_time = 0; + access_record.read_count = 0; + access_record.write_count = 0; + endfunction +endclass + + + diff --git a/test_regress/t/t_uvm/base/uvm_resource_db.svh b/test_regress/t/t_uvm/base/uvm_resource_db.svh new file mode 100644 index 0000000000..8ab1d384a4 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_resource_db.svh @@ -0,0 +1,382 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Paradigm Works +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2017 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, Inc. +// Copyright 2011 Cypress Semiconductor Corp. +// Copyright 2017 Verific +// 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM Resource Database +// +// Topic: Intro +// +// The class provides a convenience interface for +// the resources facility. In many cases basic operations such as +// creating and setting a resource or getting a resource could take +// multiple lines of code using the interfaces in or +// . The convenience layer in +// reduces many of those operations to a single line of code. +// +// If the run-time ~+UVM_RESOURCE_DB_TRACE~ command line option is +// specified, all resource DB accesses (read and write) are displayed. +//---------------------------------------------------------------------- + +typedef class uvm_resource_db_options; +typedef class uvm_cmdline_processor; + + +// Class: uvm_resource_db +// Implementation of uvm_resource_db, as defined in section +// C.3.2.1 of 1800.2-2017. +// +//| class uvm_resource_db#(type T=uvm_object) + +// @uvm-ieee 1800.2-2017 auto C.3.2.1 +class uvm_resource_db #(type T=uvm_object); + + typedef uvm_resource #(T) rsrc_t; + + protected function new(); + endfunction + + // function -- NODOCS -- get_by_type + // + // Get a resource by type. The type is specified in the db + // class parameter so the only argument to this function is the + // ~scope~. + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.5 + static function rsrc_t get_by_type(string scope); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + rsrc_t rsrc; + string msg; + uvm_resource_base type_handle = rsrc_t::get_type(); + + if(type_handle == null) + return null; + + rsrc_base = rp.get_by_type(scope, type_handle); + if(!$cast(rsrc, rsrc_base)) begin + $sformat(msg, "Resource with specified type handle in scope %s was not located", scope); + `uvm_warning("RSRCNF", msg) + return null; + end + + return rsrc; + endfunction + + // function -- NODOCS -- get_by_name + // + // Imports a resource by ~name~. The first argument is the current + // ~scope~ of the resource to be retrieved and the second argument is + // the ~name~. The ~rpterr~ flag indicates whether or not to generate + // a warning if no matching resource is found. + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.4 + static function rsrc_t get_by_name(string scope, + string name, + bit rpterr=1); + + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + rsrc_t rsrc; + string msg; + + rsrc_base = rp.get_by_name(scope, name, rsrc_t::get_type(), rpterr); + if(rsrc_base == null) + return null; + + if(!$cast(rsrc, rsrc_base)) begin + if(rpterr) begin + $sformat(msg, "Resource with name %s in scope %s has incorrect type", name, scope); + `uvm_warning("RSRCTYPE", msg) + end + return null; + end + + return rsrc; + endfunction + + // function -- NODOCS -- set_default + // + // add a new item into the resources database. The item will not be + // written to so it will have its default value. The resource is + // created using ~name~ and ~scope~ as the lookup parameters. + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.2 + static function rsrc_t set_default(string scope, string name); + + rsrc_t r; + uvm_resource_pool rp = uvm_resource_pool::get(); + + r = new(name); + rp.set_scope(r, scope); + return r; + endfunction + + // function- show_msg + + // internal helper function to print resource accesses + + protected static function void m_show_msg( + input string id, + input string rtype, + input string action, + input string scope, + input string name, + input uvm_object accessor, + input rsrc_t rsrc); + + T foo; + string msg=`uvm_typename(foo); + + $sformat(msg, "%s scope='%s' name='%s' (type %s) %s accessor=%s = %s", + rtype,scope,name, msg,action, + (accessor != null) ? accessor.get_full_name() : "", + rsrc==null?"null (failed lookup)":rsrc.convert2string()); + + `uvm_info(id, msg, UVM_LOW) + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.1 + static function void set(input string scope, input string name, + T val, input uvm_object accessor = null); + + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_scope(rsrc, scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SET", "Resource","set", scope, name, accessor, rsrc); + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.3 + static function void set_anonymous(input string scope, + T val, input uvm_object accessor = null); + + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(""); + rsrc.write(val, accessor); + rp.set_scope(rsrc, scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETANON","Resource", "set", scope, "", accessor, rsrc); + endfunction + + // function set_override + // + // Create a new resource, write ~val~ to it, and set it into the + // database. Set it at the beginning of the queue in the type map and + // the name map so that it will be (currently) the highest priority + // resource with the specified name and type. + + static function void set_override(input string scope, input string name, + T val, uvm_object accessor = null); + + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_override(rsrc, scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRD", "Resource","set", scope, name, accessor, rsrc); + endfunction + + + + // function set_override_type + // + // Create a new resource, write ~val~ to it, and set it into the + // database. Set it at the beginning of the queue in the type map so + // that it will be (currently) the highest priority resource with the + // specified type. It will be normal priority (i.e. at the end of the + // queue) in the name map. + + static function void set_override_type(input string scope, input string name, + T val, uvm_object accessor = null); + + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_type_override(rsrc, scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRDTYP","Resource", "set", scope, name, accessor, rsrc); + endfunction + + // function set_override_name + // + // Create a new resource, write ~val~ to it, and set it into the + // database. Set it at the beginning of the queue in the name map so + // that it will be (currently) the highest priority resource with the + // specified name. It will be normal priority (i.e. at the end of the + // queue) in the type map. + + static function void set_override_name(input string scope, input string name, + T val, uvm_object accessor = null); + + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_name_override(rsrc, scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRDNAM","Resource", "set", scope, name, accessor, rsrc); + endfunction + + + // function: read_by_name + // + // Locates a resource by name and scope and reads its value. The value is returned through the inout argument + // val. The return value is a bit that indicates whether or not the read was successful. The accessor is available + // for an implementation to use for debug purposes only; its value shall have no functional effect on outcome + // of this method. + // + // *Note:* This function deviates from IEEE 1800.2-2017 LRM as it defines the ~val~ argument as inout, + // whereas the LRM defines it as an output. + // + //| static function bit read_by_name(input string scope, + //| input string name, + //| inout T val, + //| input uvm_object accessor = null); + // + // The implementation treats the argument as inout for cases where a read may fail + // and the value will not change from its original supplied value. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.6 + static function bit read_by_name(input string scope, + input string name, + inout T val, input uvm_object accessor = null); + + rsrc_t rsrc = get_by_name(scope, name); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/RDBYNAM","Resource", "read", scope, name, accessor, rsrc); + + if(rsrc == null) + return 0; + + val = rsrc.read(accessor); + + return 1; + + endfunction + + // function: read_by_type + // + // Reads a value by type. The value is returned through the inout argument val. The scope is used for the + // lookup. The return value is a bit that indicates whether or not the read is successful. The accessor is + // available for an implementation to use for debug purposes only; its value shall have no functional effect on + // outcome of this method. + // + // *Note:* This function deviates from IEEE 1800.2-2017 LRM as it defines the argument as inout, whereas the + // LRM defines it as an output. + // + //| static function bit read_by_type(input string scope, + //| inout T val, + //| input uvm_object accessor = null); + // + // The implementation treats the argument as inout for cases where a read may fail + // and the value will not change from its original supplied value. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.7 + static function bit read_by_type(input string scope, + inout T val, + input uvm_object accessor = null); + + rsrc_t rsrc = get_by_type(scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/RDBYTYP", "Resource","read", scope, "", accessor, rsrc); + + if(rsrc == null) + return 0; + + val = rsrc.read(accessor); + + return 1; + + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.8 + static function bit write_by_name(input string scope, input string name, + input T val, input uvm_object accessor = null); + + rsrc_t rsrc = get_by_name(scope, name); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/WR","Resource", "written", scope, name, accessor, rsrc); + + if(rsrc == null) + return 0; + + rsrc.write(val, accessor); + + return 1; + + endfunction + + + // @uvm-ieee 1800.2-2017 auto C.3.2.2.9 + static function bit write_by_type(input string scope, + input T val, input uvm_object accessor = null); + + rsrc_t rsrc = get_by_type(scope); + + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/WRTYP", "Resource","written", scope, "", accessor, rsrc); + + if(rsrc == null) + return 0; + + rsrc.write(val, accessor); + + return 1; + endfunction + + // function -- NODOCS -- dump + // + // Dump all the resources in the resource pool. This is useful for + // debugging purposes. This function does not use the parameter T, so + // it will dump the same thing -- the entire database -- no matter the + // value of the parameter. + + static function void dump(); + uvm_resource_pool rp = uvm_resource_pool::get(); + rp.dump(); + endfunction + +endclass + + diff --git a/test_regress/t/t_uvm/base/uvm_resource_db_options.svh b/test_regress/t/t_uvm/base/uvm_resource_db_options.svh new file mode 100644 index 0000000000..c3f6262b9e --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_resource_db_options.svh @@ -0,0 +1,108 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM Resource Database +// +// Topic: Intro +// +// The class provides a convenience interface for +// the resources facility. In many cases basic operations such as +// creating and setting a resource or getting a resource could take +// multiple lines of code using the interfaces in or +// . The convenience layer in +// reduces many of those operations to a single line of code. +// +// If the run-time ~+UVM_RESOURCE_DB_TRACE~ command line option is +// specified, all resource DB accesses (read and write) are displayed. +//---------------------------------------------------------------------- + + + +//---------------------------------------------------------------------- +// Class: uvm_resource_db_options +// +// This class contains static functions for manipulating and +// retrieving options that control the behavior of the +// resources DB facility. +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 +//---------------------------------------------------------------------- +class uvm_resource_db_options; + + static local bit ready; + static local bit tracing; + + // Function: turn_on_tracing + // + // Turn tracing on for the resource database. This causes all + // reads and writes to the database to display information about + // the accesses. Tracing is off by default. + // + // This method is implicitly called by the ~+UVM_RESOURCE_DB_TRACE~. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + static function void turn_on_tracing(); + if (!ready) init(); + tracing = 1; + endfunction + + // Function: turn_off_tracing + // + // Turn tracing off for the resource database. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + static function void turn_off_tracing(); + if (!ready) init(); + tracing = 0; + endfunction + + // Function: is_tracing + // + // Returns 1 if the tracing facility is on and 0 if it is off. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + + static function bit is_tracing(); + if (!ready) init(); + return tracing; + endfunction + + + static local function void init(); + uvm_cmdline_processor clp; + string trace_args[$]; + + clp = uvm_cmdline_processor::get_inst(); + + if (clp.get_arg_matches("+UVM_RESOURCE_DB_TRACE", trace_args)) begin + tracing = 1; + end + + ready = 1; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_resource_specializations.svh b/test_regress/t/t_uvm/base/uvm_resource_specializations.svh new file mode 100644 index 0000000000..86805658d6 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_resource_specializations.svh @@ -0,0 +1,197 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2018 NVIDIA Corporation +// Copyright 2017 Verific +// 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. +//---------------------------------------------------------------------- + +// macro - UVM_RESOURCE_GET_FCNS + +// When specicializing resources the get_by_name and get_by_type +// functions must be redefined. The reason is that the version of these +// functions in the base class (uvm_resource#(T)) returns an object of +// type uvm_resource#(T). In the specializations we must return an +// object of the type of the specialization. So, we call the base_class +// implementation of these functions and then downcast to the subtype. +// +// This macro is invokved once in each where a resource specialization +// is a class defined as: +// +//| class extends uvm_resource#(T) +// +// where is the name of the derived class. +// The argument to this macro is T, the type of the uvm_resource#(T) +// specialization. The class in which the macro is defined must supply +// a typedef of the specialized class of the form: +// +//| typedef this_subtype; +// +// where is the same as above. The macro +// generates the get_by_name() and get_by_type() functions for the +// specialized resource (i.e. resource subtype). + +`define UVM_RESOURCE_GET_FCNS(base_type) \ + static function this_subtype get_by_name(string scope, string name, bit rpterr = 1); \ + this_subtype t; \ + uvm_resource_base b = uvm_resource#(base_type)::get_by_name(scope, name, rpterr); \ + if(!$cast(t, b)) \ + `uvm_fatal("BADCAST", "cannot cast resource to resource subtype") \ + return t; \ + endfunction \ + \ + static function this_subtype get_by_type(string scope = "", \ + uvm_resource_base type_handle); \ + this_subtype t; \ + uvm_resource_base b = uvm_resource#(base_type)::get_by_type(scope, type_handle); \ + if(!$cast(t, b)) \ + `uvm_fatal("BADCAST", "cannot cast resource to resource subtype") \ + return t; \ + endfunction + + +//---------------------------------------------------------------------- +// uvm_int_rsrc +// +// specialization of uvm_resource #(T) for T = int +//---------------------------------------------------------------------- +class uvm_int_rsrc extends uvm_resource #(int); + + typedef uvm_int_rsrc this_subtype; + + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + + function string convert2string(); + string s; + $sformat(s, "%0d", read()); + return s; + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + `UVM_RESOURCE_GET_FCNS(int) +`endif // UVM_ENABLE_DEPRECATED_API + +endclass + +//---------------------------------------------------------------------- +// uvm_string_rsrc +// +// specialization of uvm_resource #(T) for T = string +//---------------------------------------------------------------------- +class uvm_string_rsrc extends uvm_resource #(string); + + typedef uvm_string_rsrc this_subtype; + + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + + function string convert2string(); + return read(); + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + `UVM_RESOURCE_GET_FCNS(string) +`endif // UVM_ENABLE_DEPRECATED_API + +endclass + +//---------------------------------------------------------------------- +// uvm_obj_rsrc +// +// specialization of uvm_resource #(T) for T = uvm_object +//---------------------------------------------------------------------- +class uvm_obj_rsrc extends uvm_resource #(uvm_object); + + typedef uvm_obj_rsrc this_subtype; + + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + `UVM_RESOURCE_GET_FCNS(uvm_object) +`endif // UVM_ENABLE_DEPRECATED_API + +endclass + +//---------------------------------------------------------------------- +// uvm_bit_rsrc +// +// specialization of uvm_resource #(T) for T = vector of bits +//---------------------------------------------------------------------- +class uvm_bit_rsrc #(int unsigned N=1) extends uvm_resource #(bit[N-1:0]); + + typedef uvm_bit_rsrc#(N) this_subtype; + + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + + function string convert2string(); + string s; + $sformat(s, "%0b", read()); + return s; + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + `UVM_RESOURCE_GET_FCNS(bit[N-1:0]) +`endif // UVM_ENABLE_DEPRECATED_API + +endclass + +//---------------------------------------------------------------------- +// uvm_byte_rsrc +// +// specialization of uvm_resource #T() for T = vector of bytes +//---------------------------------------------------------------------- +class uvm_byte_rsrc #(int unsigned N=1) extends uvm_resource #(bit[7:0][N-1:0]); + + typedef uvm_byte_rsrc#(N) this_subtype; + + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + + function string convert2string(); + string s; + $sformat(s, "%0x", read()); + return s; + endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API + `UVM_RESOURCE_GET_FCNS(bit[7:0][N-1:0]) +`endif // UVM_ENABLE_DEPRECATED_API + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_root.svh b/test_regress/t/t_uvm/base/uvm_root.svh index b5c879525e..c2b6b674a3 100644 --- a/test_regress/t/t_uvm/base/uvm_root.svh +++ b/test_regress/t/t_uvm/base/uvm_root.svh @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 // //------------------------------------------------------------------------------ // Copyright 2007-2011 Mentor Graphics Corporation @@ -27,61 +26,1129 @@ // permissions and limitations under the License. //------------------------------------------------------------------------------ -//-!!!- NOTICE -------------------------------------------------------------!!!- -// This is a non-production-ready modified version of UVM intended for coverage -// testing purpouses -//-!!!----------------------------------------------------------------------!!!- +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_root +// +// The ~uvm_root~ class serves as the implicit top-level and phase controller for +// all UVM components. Users do not directly instantiate ~uvm_root~. The UVM +// automatically creates a single instance of that users can +// access via the global (uvm_pkg-scope) variable, ~uvm_top~. +// +// (see uvm_ref_root.gif) +// +// The ~uvm_top~ instance of ~uvm_root~ plays several key roles in the UVM. +// +// Implicit top-level - The ~uvm_top~ serves as an implicit top-level component. +// Any component whose parent is specified as ~null~ becomes a child of ~uvm_top~. +// Thus, all UVM components in simulation are descendants of ~uvm_top~. +// +// Phase control - ~uvm_top~ manages the phasing for all components. +// +// Search - Use ~uvm_top~ to search for components based on their +// hierarchical name. See and . +// +// Report configuration - Use ~uvm_top~ to globally configure +// report verbosity, log files, and actions. For example, +// ~uvm_top.set_report_verbosity_level_hier(UVM_FULL)~ would set +// full verbosity for all components in simulation. +// +// Global reporter - Because ~uvm_top~ is globally accessible (in uvm_pkg +// scope), UVM's reporting mechanism is accessible from anywhere +// outside ~uvm_component~, such as in modules and sequences. +// See , , and other global +// methods. +// +// +// The ~uvm_top~ instance checks during the end_of_elaboration phase if any errors have +// been generated so far. If errors are found a UVM_FATAL error is being generated as result +// so that the simulation will not continue to the start_of_simulation_phase. +// + +//------------------------------------------------------------------------------ + +typedef class uvm_cmdline_processor; +typedef class uvm_component_proxy; +typedef class uvm_top_down_visitor_adapter; +typedef class uvm_report_message; +typedef class uvm_report_object; +typedef class uvm_report_handler; +typedef class uvm_default_report_server; + +// Class: uvm_root +// +//| class uvm_root extends uvm_component +// +// Implementation of the uvm_root class, as defined +// in 1800.2-2017 Section F.7 + +//@uvm-ieee 1800.2-2017 manual F.7 class uvm_root extends uvm_component; - //UVM static local uvm_root m_inst; - static uvm_root m_inst; - //UVM - extern protected function new (); - extern static function uvm_root m_uvm_get_root(); + // Function -- NODOCS -- get() + // Static accessor for . + // + // The static accessor is provided as a convenience wrapper + // around retrieving the root via the + // method. + // + // | // Using the uvm_coreservice_t: + // | uvm_coreservice_t cs; + // | uvm_root r; + // | cs = uvm_coreservice_t::get(); + // | r = cs.get_root(); + // | + // | // Not using the uvm_coreservice_t: + // | uvm_root r; + // | r = uvm_root::get(); + // + + extern static function uvm_root get(); + + uvm_cmdline_processor clp; + + virtual function string get_type_name(); + return "uvm_root"; + endfunction + + + //---------------------------------------------------------------------------- + // Group -- NODOCS -- Simulation Control + //---------------------------------------------------------------------------- + + + // Task -- NODOCS -- run_test + // + // Phases all components through all registered phases. If the optional + // test_name argument is provided, or if a command-line plusarg, + // +UVM_TESTNAME=TEST_NAME, is found, then the specified component is created + // just prior to phasing. The test may contain new verification components or + // the entire testbench, in which case the test and testbench can be chosen from + // the command line without forcing recompilation. If the global (package) + // variable, finish_on_completion, is set, then $finish is called after + // phasing completes. + + extern virtual task run_test (string test_name=""); + + + // Function -- NODOCS -- die + // + // This method is called by the report server if a report reaches the maximum + // quit count or has a UVM_EXIT action associated with it, e.g., as with + // fatal errors. + // + // Calls the method + // on the entire hierarchy in a bottom-up fashion. + // It then calls and terminates the simulation + // with ~$finish~. + + virtual function void die(); + uvm_report_server l_rs = uvm_report_server::get_server(); + // do the pre_abort callbacks + + m_uvm_core_state=UVM_CORE_PRE_ABORT; + + + m_do_pre_abort(); + + uvm_run_test_callback::m_do_pre_abort(); + + l_rs.report_summarize(); + + m_uvm_core_state=UVM_CORE_ABORTED; + + $finish; + endfunction + + + // Function -- NODOCS -- set_timeout + // + // Specifies the timeout for the simulation. Default is <`UVM_DEFAULT_TIMEOUT> + // + // The timeout is simply the maximum absolute simulation time allowed before a + // ~FATAL~ occurs. If the timeout is set to 20ns, then the simulation must end + // before 20ns, or a ~FATAL~ timeout will occur. + // + // This is provided so that the user can prevent the simulation from potentially + // consuming too many resources (Disk, Memory, CPU, etc) when the testbench is + // essentially hung. + // + // + + extern function void set_timeout(time timeout, bit overridable=1); + + // Variable -- NODOCS -- finish_on_completion + // + // If set, then run_test will call $finish after all phases are executed. + +`ifdef UVM_ENABLE_DEPRECATED_API + bit finish_on_completion = 1; +`else + local bit finish_on_completion = 1; +`endif + + // Function -- NODOCS -- get_finish_on_completion + + virtual function bit get_finish_on_completion(); + return finish_on_completion; + endfunction : get_finish_on_completion + + // Function -- NODOCS -- set_finish_on_completion + + virtual function void set_finish_on_completion(bit f); + finish_on_completion = f; + endfunction : set_finish_on_completion + +//---------------------------------------------------------------------------- +// Group -- NODOCS -- Topology +//---------------------------------------------------------------------------- + +`ifdef UVM_ENABLE_DEPRECATED_API + // Variable -- NODOCS -- top_levels + // + // This variable is a list of all of the top level components in UVM. It + // includes the uvm_test_top component that is created by as + // well as any other top level components that have been instantiated + // anywhere in the hierarchy. + + uvm_component top_levels[$]; +`endif // UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- find + + extern function uvm_component find (string comp_match); + + // Function -- NODOCS -- find_all + // + // Returns the component handle (find) or list of components handles + // (find_all) matching a given string. The string may contain the wildcards, + // * and ?. Strings beginning with '.' are absolute path names. If the optional + // argument comp is provided, then search begins from that component down + // (default=all components). + + extern function void find_all (string comp_match, + ref uvm_component comps[$], + input uvm_component comp=null); + + + // Function -- NODOCS -- print_topology + // + // Print the verification environment's component topology. The + // ~printer~ is a object that controls the format + // of the topology printout; a ~null~ printer prints with the + // default output. + + extern function void print_topology (uvm_printer printer=null); + + + // Variable -- NODOCS -- enable_print_topology + // + // If set, then the entire testbench topology is printed just after completion + // of the end_of_elaboration phase. + + bit enable_print_topology = 0; + + + // Function: set_enable_print_topology + // + //| function void set_enable_print_topology (bit enable) + // + // Sets the variable to enable printing the entire testbench topology just after completion + // of the end_of_elaboration phase. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + extern function void set_enable_print_topology (bit enable); + + // Function: get_enable_print_topology + // + //| function bit get_enable_print_topology() + // + // Gets the variable to enable printing the entire testbench topology just after completion. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + extern function bit get_enable_print_topology (); + + + // Variable- phase_timeout + // + // Specifies the timeout for the run phase. Default is `UVM_DEFAULT_TIMEOUT + + + time phase_timeout = `UVM_DEFAULT_TIMEOUT; + + + // PRIVATE members + extern function void m_find_all_recurse(string comp_match, + ref uvm_component comps[$], + input uvm_component comp=null); + + extern protected function new (); + extern protected virtual function bit m_add_child (uvm_component child); + extern function void build_phase(uvm_phase phase); + extern local function void m_do_verbosity_settings(); + extern local function void m_do_timeout_settings(); + extern local function void m_do_factory_settings(); + extern local function void m_process_inst_override(string ovr); + extern local function void m_process_type_override(string ovr); + extern local function void m_do_config_settings(); + extern local function void m_do_max_quit_settings(); + extern local function void m_do_dump_args(); + extern local function void m_process_config(string cfg, bit is_int); + extern local function void m_process_default_sequence(string cfg); + extern function void m_check_verbosity(); + extern function void m_check_uvm_field_flag_size(); + extern virtual function void report_header(UVM_FILE file = 0); + // singleton handle + static local uvm_root m_inst; + + // For error checking + extern virtual task run_phase (uvm_phase phase); + + + // phase_started + // ------------- + // At end of elab phase we need to do tlm binding resolution. + function void phase_started(uvm_phase phase); + if (phase == end_of_elaboration_ph) begin + do_resolve_bindings(); + if (enable_print_topology) print_topology(); + begin + uvm_report_server srvr; + srvr = uvm_report_server::get_server(); + if(srvr.get_severity_count(UVM_ERROR) > 0) begin + uvm_report_fatal("BUILDERR", "stopping due to build errors", UVM_NONE); + end + end + end + endfunction + + bit m_phase_all_done; + + extern static function uvm_root m_uvm_get_root(); + + + static local bit m_relnotes_done=0; + + function void end_of_elaboration_phase(uvm_phase phase); + uvm_component_proxy p = new("proxy"); + uvm_top_down_visitor_adapter#(uvm_component) adapter = new("adapter"); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_visitor#(uvm_component) v = cs.get_component_visitor(); + adapter.accept(this, v, p); + endfunction + endclass -// UVM ~ +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_root uvm_top ; //Note this is no longer const as we assign it in uvm_root::new() to avoid static init races +`endif + + +//----------------------------------------------------------------------------- +// IMPLEMENTATION +//----------------------------------------------------------------------------- + +// get +// --- + +function uvm_root uvm_root::get(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_root(); +endfunction + +// new +// --- + function uvm_root::new(); - //UVM uvm_report_handler rh; + uvm_report_handler rh; super.new("__top__", null); // For error reporting purposes, we need to construct this first. - //UVM rh = new("reporter"); - //UVM set_report_handler(rh); + rh = new("reporter"); + set_report_handler(rh); // Checking/Setting this here makes it much harder to // trick uvm_init into infinite recursions if (m_inst != null) begin - //UVM `uvm_fatal_context("UVM/ROOT/MULTI", - //UVM "Attempting to construct multiple roots", - //UVM m_inst) - $display("UVM/ROOT/MULTI: Attempting to construct multiple roots"); - //UVM + `uvm_fatal_context("UVM/ROOT/MULTI", + "Attempting to construct multiple roots", + m_inst) return; end m_inst = this; `ifdef UVM_ENABLE_DEPRECATED_API - uvm_top = this; + uvm_top = this; `endif - //UVM clp = uvm_cmdline_processor::get_inst(); + clp = uvm_cmdline_processor::get_inst(); endfunction -// UVM ~ +// m_uvm_get_root +// internal function not to be used +// get the initialized singleton instance of uvm_root function uvm_root uvm_root::m_uvm_get_root(); if (m_inst == null) begin uvm_root top; top = new(); - + if (top != m_inst) // Something very, very bad has happened and // we already fatal'd. Throw out the garbage // root. return null; - - //UVM top.m_domain = uvm_domain::get_uvm_domain(); + + top.m_domain = uvm_domain::get_uvm_domain(); end return m_inst; endfunction + + +function void uvm_root::report_header(UVM_FILE file = 0); + string q[$]; + uvm_report_server srvr; + uvm_cmdline_processor clp; + string args[$]; + + srvr = uvm_report_server::get_server(); + clp = uvm_cmdline_processor::get_inst(); + + if (clp.get_arg_matches("+UVM_NO_RELNOTES", args)) return; + + if (!m_relnotes_done) begin + q.push_back("\n *********** IMPORTANT RELEASE NOTES ************\n"); + m_relnotes_done = 1; + + q.push_back("\n This implementation of the UVM Library deviates from the 1800.2-2017\n"); + q.push_back(" standard. See the DEVIATIONS.md file contained in the release\n"); + q.push_back(" for more details.\n"); + +`ifdef UVM_ENABLE_DEPRECATED_API + + q.push_back("\n You are using a version of the UVM library that has been compiled\n"); + q.push_back(" with `UVM_ENABLE_DEPRECATED_API defined.\n"); + q.push_back(" See https://accellera.mantishub.io/view.php?id=5072 for more details.\n"); + +`endif + + end // !m_relnotes_done + + q.push_back("\n----------------------------------------------------------------\n"); + q.push_back({uvm_revision_string(),"\n"}); + q.push_back("\n"); + q.push_back("All copyright owners for this kit are listed in NOTICE.txt\n"); + q.push_back("All Rights Reserved Worldwide\n"); + q.push_back("----------------------------------------------------------------\n"); + + if(m_relnotes_done) + q.push_back("\n (Specify +UVM_NO_RELNOTES to turn off this notice)\n"); + + `uvm_info("UVM/RELNOTES",`UVM_STRING_QUEUE_STREAMING_PACK(q),UVM_LOW) +endfunction + + + +// run_test +// -------- + +task uvm_root::run_test(string test_name=""); + uvm_report_server l_rs; + + uvm_factory factory; + bit testname_plusarg; + int test_name_count; + string test_names[$]; + string msg; + uvm_component uvm_test_top; + + process phase_runner_proc; // store thread forked below for final cleanup + + uvm_run_test_callback::m_do_pre_run_test(); + + factory=uvm_factory::get(); + m_uvm_core_state=UVM_CORE_PRE_RUN; + + testname_plusarg = 0; + + // Set up the process that decouples the thread that drops objections from + // the process that processes drop/all_dropped objections. Thus, if the + // original calling thread (the "dropper") gets killed, it does not affect + // drain-time and propagation of the drop up the hierarchy. + // Needs to be done in run_test since it needs to be in an + // initial block to fork a process. + uvm_objection::m_init_objections(); + +// dump cmdline args BEFORE the args are being used + m_do_dump_args(); + +`ifndef UVM_NO_DPI + + // Retrieve the test names provided on the command line. Command line + // overrides the argument. + test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names); + + // If at least one, use first in queue. + if (test_name_count > 0) begin + test_name = test_names[0]; + testname_plusarg = 1; + end + + // If multiple, provided the warning giving the number, which one will be + // used and the complete list. + if (test_name_count > 1) begin + string test_list; + string sep; + for (int i = 0; i < test_names.size(); i++) begin + if (i != 0) + sep = ", "; + test_list = {test_list, sep, test_names[i]}; + end + uvm_report_warning("MULTTST", + $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line. '%s' will be used. Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE); + end + +`else + + // plusarg overrides argument + if ($value$plusargs("UVM_TESTNAME=%s", test_name)) begin + `uvm_info("NO_DPI_TSTNAME", "UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI", UVM_NONE) + testname_plusarg = 1; + end + +`endif + + // if test now defined, create it using common factory + if (test_name != "") begin + + if(m_children.exists("uvm_test_top")) begin + uvm_report_fatal("TTINST", + "An uvm_test_top already exists via a previous call to run_test", UVM_NONE); + #0; // forces shutdown because $finish is forked + end + $cast(uvm_test_top, factory.create_component_by_name(test_name, + "", "uvm_test_top", null)); + + if (uvm_test_top == null) begin + msg = testname_plusarg ? {"command line +UVM_TESTNAME=",test_name} : + {"call to run_test(",test_name,")"}; + uvm_report_fatal("INVTST", + {"Requested test from ",msg, " not found." }, UVM_NONE); + end + end + + if (m_children.num() == 0) begin + uvm_report_fatal("NOCOMP", + {"No components instantiated. You must either instantiate", + " at least one component before calling run_test or use", + " run_test to do so. To run a test using run_test,", + " use +UVM_TESTNAME or supply the test name in", + " the argument to run_test(). Exiting simulation."}, UVM_NONE); + return; + end + + begin + if(test_name=="") + uvm_report_info("RNTST", "Running test ...", UVM_LOW); + else if (test_name == uvm_test_top.get_type_name()) + uvm_report_info("RNTST", {"Running test ",test_name,"..."}, UVM_LOW); + else + uvm_report_info("RNTST", {"Running test ",uvm_test_top.get_type_name()," (via factory override for test \"",test_name,"\")..."}, UVM_LOW); + end + + // phase runner, isolated from calling process + fork begin + // spawn the phase runner task + phase_runner_proc = process::self(); + uvm_phase::m_run_phases(); + end + join_none + #0; // let the phase runner start + + wait (m_phase_all_done == 1); + + m_uvm_core_state=UVM_CORE_POST_RUN; + + // clean up after ourselves + phase_runner_proc.kill(); + + l_rs = uvm_report_server::get_server(); + + uvm_run_test_callback::m_do_post_run_test(); + + l_rs.report_summarize(); + + m_uvm_core_state=UVM_CORE_FINISHED; + if (get_finish_on_completion()) + $finish; + +endtask + + +// find_all +// -------- + +function void uvm_root::find_all(string comp_match, ref uvm_component comps[$], + input uvm_component comp=null); + + if (comp==null) + comp = this; + m_find_all_recurse(comp_match, comps, comp); + +endfunction + + +// find +// ---- + +function uvm_component uvm_root::find (string comp_match); + uvm_component comp_list[$]; + + find_all(comp_match,comp_list); + + if (comp_list.size() > 1) + uvm_report_warning("MMATCH", + $sformatf("Found %0d components matching '%s'. Returning first match, %0s.", + comp_list.size(),comp_match,comp_list[0].get_full_name()), UVM_NONE); + + if (comp_list.size() == 0) begin + uvm_report_warning("CMPNFD", + {"Component matching '",comp_match, + "' was not found in the list of uvm_components"}, UVM_NONE); + return null; + end + + return comp_list[0]; +endfunction + + +// print_topology +// -------------- + +function void uvm_root::print_topology(uvm_printer printer=null); + + if (m_children.num()==0) begin + uvm_report_warning("EMTCOMP", "print_topology - No UVM components to print.", UVM_NONE); + return; + end + + if (printer==null) + printer = uvm_printer::get_default(); + + `uvm_info("UVMTOP","UVM testbench topology:",UVM_NONE) + print(printer) ; + +endfunction + + +// set_timeout +// ----------- + +function void uvm_root::set_timeout(time timeout, bit overridable=1); + static bit m_uvm_timeout_overridable = 1; + if (m_uvm_timeout_overridable == 0) begin + uvm_report_info("NOTIMOUTOVR", + $sformatf("The global timeout setting of %0d is not overridable to %0d due to a previous setting.", + phase_timeout, timeout), UVM_NONE); + return; + end + m_uvm_timeout_overridable = overridable; + phase_timeout = timeout; +endfunction + + + +// m_find_all_recurse +// ------------------ + +function void uvm_root::m_find_all_recurse(string comp_match, ref uvm_component comps[$], + input uvm_component comp=null); + string name; + + if (comp.get_first_child(name)) + do begin + this.m_find_all_recurse(comp_match, comps, comp.get_child(name)); + end + while (comp.get_next_child(name)); + if (uvm_is_match(comp_match, comp.get_full_name()) && + comp.get_name() != "") /* uvm_top */ + comps.push_back(comp); + +endfunction + + +// m_add_child +// ----------- + +// Add to the top levels array +function bit uvm_root::m_add_child (uvm_component child); + if(super.m_add_child(child)) begin +`ifdef UVM_ENABLE_DEPRECATED_API + if(child.get_name() == "uvm_test_top") + top_levels.push_front(child); + else + top_levels.push_back(child); +`endif // UVM_ENABLE_DEPRECATED_API + return 1; + end + else + return 0; +endfunction + + +// build_phase +// ----- + +function void uvm_root::build_phase(uvm_phase phase); + + super.build_phase(phase); + + m_set_cl_msg_args(); + + m_do_verbosity_settings(); + m_do_timeout_settings(); + m_do_factory_settings(); + m_do_config_settings(); + m_do_max_quit_settings(); + +endfunction + + +// m_do_verbosity_settings +// ----------------------- + +function void uvm_root::m_do_verbosity_settings(); + string set_verbosity_settings[$]; + string split_vals[$]; + uvm_verbosity tmp_verb; + + // Retrieve them all into set_verbosity_settings + void'(clp.get_arg_values("+uvm_set_verbosity=", set_verbosity_settings)); + + for(int i = 0; i < set_verbosity_settings.size(); i++) begin + uvm_split_string(set_verbosity_settings[i], ",", split_vals); + if(split_vals.size() < 4 || split_vals.size() > 5) begin + uvm_report_warning("INVLCMDARGS", + $sformatf("Invalid number of arguments found on the command line for setting '+uvm_set_verbosity=%s'. Setting ignored.", + set_verbosity_settings[i]), UVM_NONE, "", ""); + end + // Invalid verbosity + if(!clp.m_convert_verb(split_vals[2], tmp_verb)) begin + uvm_report_warning("INVLCMDVERB", + $sformatf("Invalid verbosity found on the command line for setting '%s'.", + set_verbosity_settings[i]), UVM_NONE, "", ""); + end + end +endfunction + + +// m_do_timeout_settings +// --------------------- + +function void uvm_root::m_do_timeout_settings(); + string timeout_settings[$]; + string timeout; + string split_timeout[$]; + int timeout_count; + time timeout_int; + string override_spec; + timeout_count = clp.get_arg_values("+UVM_TIMEOUT=", timeout_settings); + if (timeout_count == 0) + return; + else begin + timeout = timeout_settings[0]; + if (timeout_count > 1) begin + string timeout_list; + string sep; + for (int i = 0; i < timeout_settings.size(); i++) begin + if (i != 0) + sep = "; "; + timeout_list = {timeout_list, sep, timeout_settings[i]}; + end + uvm_report_warning("MULTTIMOUT", + $sformatf("Multiple (%0d) +UVM_TIMEOUT arguments provided on the command line. '%s' will be used. Provided list: %s.", + timeout_count, timeout, timeout_list), UVM_NONE); + end + uvm_report_info("TIMOUTSET", + $sformatf("'+UVM_TIMEOUT=%s' provided on the command line is being applied.", timeout), UVM_NONE); + void'($sscanf(timeout,"%d,%s",timeout_int,override_spec)); + case(override_spec) + "YES" : set_timeout(timeout_int, 1); + "NO" : set_timeout(timeout_int, 0); + default : set_timeout(timeout_int, 1); + endcase + end +endfunction + + +// m_do_factory_settings +// --------------------- + +function void uvm_root::m_do_factory_settings(); + string args[$]; + + void'(clp.get_arg_matches("/^\\+(UVM_SET_INST_OVERRIDE|uvm_set_inst_override)=/",args)); + foreach(args[i]) begin + m_process_inst_override(args[i].substr(23, args[i].len()-1)); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_TYPE_OVERRIDE|uvm_set_type_override)=/",args)); + foreach(args[i]) begin + m_process_type_override(args[i].substr(23, args[i].len()-1)); + end +endfunction + + +// m_process_inst_override +// ----------------------- + +function void uvm_root::m_process_inst_override(string ovr); + string split_val[$]; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + + uvm_split_string(ovr, ",", split_val); + + if(split_val.size() != 3 ) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid setting for +uvm_set_inst_override=", ovr, + ", setting must specify ,,"}, UVM_NONE); + return; + end + + uvm_report_info("INSTOVR", {"Applying instance override from the command line: +uvm_set_inst_override=", ovr}, UVM_NONE); + factory.set_inst_override_by_name(split_val[0], split_val[1], split_val[2]); +endfunction + + +// m_process_type_override +// ----------------------- + +function void uvm_root::m_process_type_override(string ovr); + string split_val[$]; + int replace=1; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + + uvm_split_string(ovr, ",", split_val); + + if(split_val.size() > 3 || split_val.size() < 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid setting for +uvm_set_type_override=", ovr, + ", setting must specify ,[,]"}, UVM_NONE); + return; + end + + // Replace arg is optional. If set, must be 0 or 1 + if(split_val.size() == 3) begin + if(split_val[2]=="0") replace = 0; + else if (split_val[2] == "1") replace = 1; + else begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid replace arg for +uvm_set_type_override=", ovr ," value must be 0 or 1"}, UVM_NONE); + return; + end + end + + uvm_report_info("UVM_CMDLINE_PROC", {"Applying type override from the command line: +uvm_set_type_override=", ovr}, UVM_NONE); + factory.set_type_override_by_name(split_val[0], split_val[1], replace); +endfunction + + +// m_process_config +// ---------------- + +function void uvm_root::m_process_config(string cfg, bit is_int); + uvm_bitstream_t v; + string split_val[$]; + uvm_root m_uvm_top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + m_uvm_top = cs.get_root(); + + + uvm_split_string(cfg, ",", split_val); + if(split_val.size() == 1) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_config command\"", cfg, + "\" missing field and value: component is \"", split_val[0], "\""}, UVM_NONE); + return; + end + + if(split_val.size() == 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_config command\"", cfg, + "\" missing value: component is \"", split_val[0], "\" field is \"", split_val[1], "\""}, UVM_NONE); + return; + end + + if(split_val.size() > 3) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid +uvm_set_config command\"%s\" : expected only 3 fields (component, field and value).", cfg), UVM_NONE); + return; + end + + if(is_int) begin + if(split_val[2].len() > 2) begin + string base, extval; + base = split_val[2].substr(0,1); + extval = split_val[2].substr(2,split_val[2].len()-1); + case(base) + "'b" : v = extval.atobin(); + "0b" : v = extval.atobin(); + "'o" : v = extval.atooct(); + "'d" : v = extval.atoi(); + "'h" : v = extval.atohex(); + "'x" : v = extval.atohex(); + "0x" : v = extval.atohex(); + default : v = split_val[2].atoi(); + endcase + end + else begin + v = split_val[2].atoi(); + end + uvm_report_info("UVM_CMDLINE_PROC", {"Applying config setting from the command line: +uvm_set_config_int=", cfg}, UVM_NONE); + uvm_config_int::set(m_uvm_top, split_val[0], split_val[1], v); + end + else begin + uvm_report_info("UVM_CMDLINE_PROC", {"Applying config setting from the command line: +uvm_set_config_string=", cfg}, UVM_NONE); + uvm_config_string::set(m_uvm_top, split_val[0], split_val[1], split_val[2]); + end + +endfunction + +// m_process_default_sequence +// ---------------- + +function void uvm_root::m_process_default_sequence(string cfg); + string split_val[$]; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_root m_uvm_top = cs.get_root(); + uvm_factory f = cs.get_factory(); + uvm_object_wrapper w; + + uvm_split_string(cfg, ",", split_val); + if(split_val.size() == 1) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_default_sequence command\"", cfg, + "\" missing phase and type: sequencer is \"", split_val[0], "\""}, UVM_NONE); + return; + end + + if(split_val.size() == 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_default_sequence command\"", cfg, + "\" missing type: sequencer is \"", split_val[0], "\" phase is \"", split_val[1], "\""}, UVM_NONE); + return; + end + + if(split_val.size() > 3) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid +uvm_set_default_sequence command\"%s\" : expected only 3 fields (sequencer, phase and type).", cfg), UVM_NONE); + return; + end + + w = f.find_wrapper_by_name(split_val[2]); + if (w == null) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid type '%s' provided to +uvm_set_default_sequence", split_val[2]), + UVM_NONE); + return; + end + else begin + uvm_report_info("UVM_CMDLINE_PROC", {"Setting default sequence from the command line: +uvm_set_default_sequence=", cfg}, UVM_NONE); + uvm_config_db#(uvm_object_wrapper)::set(this, {split_val[0], ".", split_val[1]}, "default_sequence", w); + end + +endfunction : m_process_default_sequence + + +// m_do_config_settings +// -------------------- + +function void uvm_root::m_do_config_settings(); + string args[$]; + + void'(clp.get_arg_matches("/^\\+(UVM_SET_CONFIG_INT|uvm_set_config_int)=/",args)); + foreach(args[i]) begin + m_process_config(args[i].substr(20, args[i].len()-1), 1); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_CONFIG_STRING|uvm_set_config_string)=/",args)); + foreach(args[i]) begin + m_process_config(args[i].substr(23, args[i].len()-1), 0); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_DEFAULT_SEQUENCE|uvm_set_default_sequence)=/", args)); + foreach(args[i]) begin + m_process_default_sequence(args[i].substr(26, args[i].len()-1)); + end +endfunction + + +// m_do_max_quit_settings +// ---------------------- + +function void uvm_root::m_do_max_quit_settings(); + uvm_report_server srvr; + string max_quit_settings[$]; + int max_quit_count; + string max_quit; + string split_max_quit[$]; + int max_quit_int; + srvr = uvm_report_server::get_server(); + max_quit_count = clp.get_arg_values("+UVM_MAX_QUIT_COUNT=", max_quit_settings); + if (max_quit_count == 0) + return; + else begin + max_quit = max_quit_settings[0]; + if (max_quit_count > 1) begin + string max_quit_list; + string sep; + for (int i = 0; i < max_quit_settings.size(); i++) begin + if (i != 0) + sep = "; "; + max_quit_list = {max_quit_list, sep, max_quit_settings[i]}; + end + uvm_report_warning("MULTMAXQUIT", + $sformatf("Multiple (%0d) +UVM_MAX_QUIT_COUNT arguments provided on the command line. '%s' will be used. Provided list: %s.", + max_quit_count, max_quit, max_quit_list), UVM_NONE); + end + uvm_report_info("MAXQUITSET", + $sformatf("'+UVM_MAX_QUIT_COUNT=%s' provided on the command line is being applied.", max_quit), UVM_NONE); + uvm_split_string(max_quit, ",", split_max_quit); + max_quit_int = split_max_quit[0].atoi(); + case(split_max_quit[1]) + "YES" : srvr.set_max_quit_count(max_quit_int, 1); + "NO" : srvr.set_max_quit_count(max_quit_int, 0); + default : srvr.set_max_quit_count(max_quit_int, 1); + endcase + end +endfunction + + +// m_do_dump_args +// -------------- + +function void uvm_root::m_do_dump_args(); + string dump_args[$]; + string all_args[$]; + string out_string; + if(clp.get_arg_matches("+UVM_DUMP_CMDLINE_ARGS", dump_args)) begin + clp.get_args(all_args); + foreach (all_args[idx]) begin + uvm_report_info("DUMPARGS", $sformatf("idx=%0d arg=[%s]",idx,all_args[idx]), UVM_NONE); + end + end +endfunction + + +// m_check_verbosity +// ---------------- + +function void uvm_root::m_check_verbosity(); + + string verb_string; + string verb_settings[$]; + int verb_count; + int plusarg; + int verbosity = UVM_MEDIUM; + + `ifndef UVM_CMDLINE_NO_DPI + // Retrieve the verbosities provided on the command line. + verb_count = clp.get_arg_values("+UVM_VERBOSITY=", verb_settings); + `else + verb_count = $value$plusargs("UVM_VERBOSITY=%s",verb_string); + if (verb_count) + verb_settings.push_back(verb_string); + `endif + + // If none provided, provide message about the default being used. + //if (verb_count == 0) + // uvm_report_info("DEFVERB", ("No verbosity specified on the command line. Using the default: UVM_MEDIUM"), UVM_NONE); + + // If at least one, use the first. + if (verb_count > 0) begin + verb_string = verb_settings[0]; + plusarg = 1; + end + + // If more than one, provide the warning stating how many, which one will + // be used and the complete list. + if (verb_count > 1) begin + string verb_list; + string sep; + for (int i = 0; i < verb_settings.size(); i++) begin + if (i != 0) + sep = ", "; + verb_list = {verb_list, sep, verb_settings[i]}; + end + uvm_report_warning("MULTVERB", + $sformatf("Multiple (%0d) +UVM_VERBOSITY arguments provided on the command line. '%s' will be used. Provided list: %s.", verb_count, verb_string, verb_list), UVM_NONE); + end + + if(plusarg == 1) begin + case(verb_string) + "UVM_NONE" : verbosity = UVM_NONE; + "NONE" : verbosity = UVM_NONE; + "UVM_LOW" : verbosity = UVM_LOW; + "LOW" : verbosity = UVM_LOW; + "UVM_MEDIUM" : verbosity = UVM_MEDIUM; + "MEDIUM" : verbosity = UVM_MEDIUM; + "UVM_HIGH" : verbosity = UVM_HIGH; + "HIGH" : verbosity = UVM_HIGH; + "UVM_FULL" : verbosity = UVM_FULL; + "FULL" : verbosity = UVM_FULL; + "UVM_DEBUG" : verbosity = UVM_DEBUG; + "DEBUG" : verbosity = UVM_DEBUG; + default : begin + verbosity = verb_string.atoi(); + if(verbosity > 0) + uvm_report_info("NSTVERB", $sformatf("Non-standard verbosity value, using provided '%0d'.", verbosity), UVM_NONE); + if(verbosity == 0) begin + verbosity = UVM_MEDIUM; + uvm_report_warning("ILLVERB", "Illegal verbosity value, using default of UVM_MEDIUM.", UVM_NONE); + end + end + endcase + end + + set_report_verbosity_level_hier(verbosity); + +endfunction + +function void uvm_root::m_check_uvm_field_flag_size(); + if ( (`UVM_FIELD_FLAG_SIZE) < UVM_FIELD_FLAG_RESERVED_BITS ) begin + uvm_report_fatal( "BAD_FIELD_FLAG_SZ", + $sformatf( + "Macro UVM_FIELD_FLAG_SIZE is set to %0d which is less than the required minimum of UVM_FIELD_FLAG_RESERVED_BITS (%0d).", + `UVM_FIELD_FLAG_SIZE, UVM_FIELD_FLAG_RESERVED_BITS + ) + ); + end +endfunction + +// It is required that the run phase start at simulation time 0 +// TBD this looks wrong - taking advantage of uvm_root not doing anything else? +// TBD move to phase_started callback? +task uvm_root::run_phase (uvm_phase phase); + // check that the commandline are took effect + foreach(m_uvm_applied_cl_action[idx]) + if(m_uvm_applied_cl_action[idx].used==0) begin + `uvm_warning("INVLCMDARGS",$sformatf("\"+uvm_set_action=%s\" never took effect due to a mismatching component pattern",m_uvm_applied_cl_action[idx].arg)) + end + foreach(m_uvm_applied_cl_sev[idx]) + if(m_uvm_applied_cl_sev[idx].used==0) begin + `uvm_warning("INVLCMDARGS",$sformatf("\"+uvm_set_severity=%s\" never took effect due to a mismatching component pattern",m_uvm_applied_cl_sev[idx].arg)) + end + + if($time > 0) + `uvm_fatal("RUNPHSTIME", {"The run phase must start at time 0, current time is ", + $sformatf("%0t", $realtime), ". No non-zero delays are allowed before ", + "run_test(), and pre-run user defined phases may not consume ", + "simulation time before the start of the run phase."}) +endtask + + +// Debug accessor methods to access enable_print_topology +function void uvm_root::set_enable_print_topology (bit enable); + enable_print_topology = enable; + +endfunction + +// Debug accessor methods to access enable_print_topology +function bit uvm_root::get_enable_print_topology(); + return enable_print_topology; +endfunction diff --git a/test_regress/t/t_uvm/base/uvm_run_test_callback.svh b/test_regress/t/t_uvm/base/uvm_run_test_callback.svh new file mode 100644 index 0000000000..f6e86e1692 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_run_test_callback.svh @@ -0,0 +1,132 @@ +// +//---------------------------------------------------------------------- +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 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. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto F.6.1 +virtual class uvm_run_test_callback extends uvm_callback; + + // @uvm-ieee 1800.2-2017 auto F.6.2.1 + // @uvm-ieee 1800.2-2017 auto F.7.1.1 + extern function new( string name="uvm_run_test_callback"); + + // @uvm-ieee 1800.2-2017 auto F.6.2.2 + virtual function void pre_run_test(); + endfunction + + // @uvm-ieee 1800.2-2017 auto F.6.2.3 + virtual function void post_run_test(); + endfunction + + // @uvm-ieee 1800.2-2017 auto F.6.2.4 + virtual function void pre_abort(); + endfunction + + // @uvm-ieee 1800.2-2017 auto F.6.2.5 + extern static function bit add( uvm_run_test_callback cb ); + + // @uvm-ieee 1800.2-2017 auto F.6.2.6 + extern static function bit delete( uvm_run_test_callback cb ); + + + // + // Implementation details. + // + + // These functions executes pre_run_test, post_run_test, and pre_abort routines for all registered + // callbacks. These are not user functions. Only uvm_root should call these. + extern static function void m_do_pre_run_test(); + extern static function void m_do_post_run_test(); + extern static function void m_do_pre_abort(); + + local static uvm_run_test_callback m_registered_cbs[$]; + +endclass : uvm_run_test_callback + + + +function uvm_run_test_callback::new( string name="uvm_run_test_callback"); + super.new( name ); +endfunction + + +// Adds cb to the list of callbacks to be processed. The method returns 1 if cb is not already in the list of +// callbacks; otherwise, a 0 is returned. If cb is null, 0 is returned. +function bit uvm_run_test_callback::add( uvm_run_test_callback cb ); + bit found; + int unsigned i; + + if ( cb == null ) begin + return 0; + end + + found = 0; + i = 0; + while ( ! found && ( i < m_registered_cbs.size() ) ) begin + if ( m_registered_cbs[ i ] == cb ) begin + found = 1; + end + ++i; + end + if ( ! found ) begin + m_registered_cbs.push_back( cb ); + end + + return ! found; +endfunction + + +// Removes cb from the list of callbacks to be processed. The method returns 1 if cb is in the list of callbacks; +// otherwise, a 0 is returned. If cb is null, 0 is returned. +function bit uvm_run_test_callback::delete( uvm_run_test_callback cb ); + int cb_idxs[$]; + + if ( cb == null ) begin + return 0; + end + + cb_idxs = m_registered_cbs.find_index( item ) with ( item == cb ); + foreach ( cb_idxs[ i ] ) begin + m_registered_cbs.delete( i ); + end + return ( cb_idxs.size() > 0 ); +endfunction + + +function void uvm_run_test_callback::m_do_pre_run_test(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].pre_run_test(); + end +endfunction + + +function void uvm_run_test_callback::m_do_post_run_test(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].post_run_test(); + end +endfunction + + +function void uvm_run_test_callback::m_do_pre_abort(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].pre_abort(); + end +endfunction + + diff --git a/test_regress/t/t_uvm/base/uvm_runtime_phases.svh b/test_regress/t/t_uvm/base/uvm_runtime_phases.svh new file mode 100644 index 0000000000..d3ac84f794 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_runtime_phases.svh @@ -0,0 +1,305 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2013 Cisco Systems, 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. +//---------------------------------------------------------------------- + +// Title -- NODOCS -- UVM Run-Time Phases +// +// The run-time schedule is the pre-defined phase schedule +// which runs concurrently to the global run phase. +// By default, all s using the run-time schedule +// are synchronized with respect to the pre-defined phases in the schedule. +// It is possible for components to belong to different domains +// in which case their schedules can be unsynchronized. +// +// The names of the UVM phases (which will be returned by get_name() for a +// phase instance) match the class names specified below with the "uvm_" +// and "_phase" removed. For example, the main phase corresponds to the +// uvm_main_phase class below and has the name "main", which means that +// the following can be used to call foo() at the start of main phase: +// +// | function void phase_started(uvm_phase phase) ; +// | if (phase.get_name()=="main") foo() ; +// | endfunction +// +// The run-time phases are executed in the sequence they are specified below. +// +// + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.1 +class uvm_pre_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_reset_phase(phase); + endtask + local static uvm_pre_reset_phase m_inst; + `uvm_type_name_decl("uvm_pre_reset_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_pre_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_reset"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.2 +class uvm_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.reset_phase(phase); + endtask + local static uvm_reset_phase m_inst; + `uvm_type_name_decl("uvm_reset_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="reset"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.3 +class uvm_post_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_reset_phase(phase); + endtask + local static uvm_post_reset_phase m_inst; + `uvm_type_name_decl("uvm_post_reset_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_post_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_reset"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.4 +class uvm_pre_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_configure_phase(phase); + endtask + local static uvm_pre_configure_phase m_inst; + `uvm_type_name_decl("uvm_pre_configure_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_pre_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_configure"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.5 +class uvm_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.configure_phase(phase); + endtask + local static uvm_configure_phase m_inst; + `uvm_type_name_decl("uvm_configure_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="configure"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.6 +class uvm_post_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_configure_phase(phase); + endtask + local static uvm_post_configure_phase m_inst; + `uvm_type_name_decl("uvm_post_configure_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_post_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_configure"); + super.new(name); + endfunction +endclass + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.7 +class uvm_pre_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_main_phase(phase); + endtask + local static uvm_pre_main_phase m_inst; + `uvm_type_name_decl("uvm_pre_main_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_pre_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_main"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.8 +class uvm_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.main_phase(phase); + endtask + local static uvm_main_phase m_inst; + `uvm_type_name_decl("uvm_main_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="main"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.9 +class uvm_post_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_main_phase(phase); + endtask + local static uvm_post_main_phase m_inst; + `uvm_type_name_decl("uvm_post_main_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_post_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_main"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.10 +class uvm_pre_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_shutdown_phase(phase); + endtask + local static uvm_pre_shutdown_phase m_inst; + `uvm_type_name_decl("uvm_pre_shutdown_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_pre_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_shutdown"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.11 +class uvm_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.shutdown_phase(phase); + endtask + local static uvm_shutdown_phase m_inst; + `uvm_type_name_decl("uvm_shutdown_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="shutdown"); + super.new(name); + endfunction +endclass + + + +// @uvm-ieee 1800.2-2017 auto 9.8.2.12 +class uvm_post_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_shutdown_phase(phase); + endtask + local static uvm_post_shutdown_phase m_inst; + `uvm_type_name_decl("uvm_post_shutdown_phase") + + // Function -- NODOCS -- get + // Returns the singleton phase handle + static function uvm_post_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_shutdown"); + super.new(name); + endfunction +endclass diff --git a/test_regress/t/t_uvm/base/uvm_spell_chkr.svh b/test_regress/t/t_uvm/base/uvm_spell_chkr.svh new file mode 100644 index 0000000000..2e569d027b --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_spell_chkr.svh @@ -0,0 +1,204 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2013 Verilab +// Copyright 2014 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. +//------------------------------------------------------------------------------ + + + +//---------------------------------------------------------------------- +// class uvm_spell_chkr +//---------------------------------------------------------------------- +class uvm_spell_chkr #(type T=int); + + typedef T tab_t[string]; + static const int unsigned max = '1; + + //-------------------------------------------------------------------- + // check + // + // primary interface to the spell checker. The function takes two + // arguments, a table of strings and a string to check. The table is + // organized as an associative array of type T. E.g. + // + // T strtab[string] + // + // It doesn't matter what T is since we are only concerned with the + // string keys. However, we need T in order to make argument types + // match. + // + // First, we do the simple thing and see if the string already is in + // the string table by calling the ~exists()~ method. If it does exist + // then there is a match and we're done. If the string doesn't exist + // in the table then we invoke the spell checker algorithm to see if + // our string is a misspelled variation on a string that does exist in + // the table. + // + // The main loop traverses the string table computing the levenshtein + // distance between each string and the string we are checking. The + // strings in the table with the minimum distance are considered + // possible alternatives. There may be more than one string in the + // table with a minimum distance. So all the alternatives are stored + // in a queue. + // + // Note: This is not a particularly efficient algorithm. It requires + // computing the levenshtein distance for every string in the string + // table. If that list were very large the run time could be long. + // For the resources application in UVM probably the size of the + // string table is not excessive and run times will be fast enough. + // If, on average, that proves to be an invalid assumption then we'll + // have to find ways to optimize this algorithm. + // + // note: strtab should not be modified inside check() + //-------------------------------------------------------------------- + static function bit check ( /* const */ ref tab_t strtab, input string s); + + string key; + int distance; + int unsigned min; + string min_key[$]; + + if(strtab.exists(s)) begin + return 1; + end + + min = max; + foreach(strtab[key]) begin + distance = levenshtein_distance(key, s); + + // A distance < 0 means either key, s, or both are empty. This + // should never happen here but we check for that condition just + // in case. + if(distance < 0) + continue; + + if(distance < min) begin + // set a new minimum. Clean out the queue since previous + // alternatives are now invalidated. + min = distance; + min_key.delete(); + min_key.push_back(key); + continue; + end + + if(distance == min) begin + min_key.push_back(key); + end + + end + + + // if (min == max) then the string table is empty + if(min == max) begin + `uvm_info("UVM/CONFIGDB/SPELLCHK",$sformatf("%s not located, no alternatives to suggest", s),UVM_NONE) + end + else + // dump all the alternatives with the minimum distance + begin + string q[$]; + + foreach(min_key[i]) begin + q.push_back(min_key[i]); + q.push_back("|"); + end + if(q.size()) + void'(q.pop_back()); + + `uvm_info("UVM/CONFIGDB/SPELLCHK",$sformatf("%s not located, did you mean %s", s, `UVM_STRING_QUEUE_STREAMING_PACK(q)),UVM_NONE) + end + + return 0; + + endfunction + + + //-------------------------------------------------------------------- + // levenshtein_distance + // + // Compute levenshtein distance between s and t + // The Levenshtein distance is defined as The smallest number of + // insertions, deletions, and substitutions required to change one + // string into another. There is a tremendous amount of information + // available on Levenshtein distance on the internet. Two good + // sources are wikipedia and nist.gov. A nice, simple explanation of + // the algorithm is at + // http://www.codeproject.com/KB/recipes/Levenshtein.aspx. Use google + // to find others. + // + // This implementation of the Levenshtein + // distance computation algorithm is a SystemVerilog adaptation of the + // C implementatiion located at http://www.merriampark.com/ldc.htm. + //-------------------------------------------------------------------- + static local function int levenshtein_distance(string s, string t); + + int k, i, j, n, m, cost, distance; + int d[]; + + //Step 1 + n = s.len() + 1; + m = t.len() + 1; + + if(n == 1 || m == 1) + return -1; //a negative return value means that one or both strings are empty. + + d = new[m*n]; + + //Step 2 + for(k = 0; k < n; k++) + d[k] = k; + + for(k = 0; k < m; k++) + d[k*n] = k; + + //Steps 3 and 4 + for(i = 1; i < n; i++) begin + for(j = 1; j < m; j++) begin + + //Step 5 + cost = !(s[i-1] == t[j-1]); + + //Step 6 + d[j*n+i] = minimum(d[(j-1)*n+i]+1, d[j*n+i-1]+1, d[(j-1)*n+i-1]+cost); + + end + end + + distance = d[n*m-1]; + return distance; + + endfunction + + //-------------------------------------------------------------------- + // Gets the minimum of three values + //-------------------------------------------------------------------- + static local function int minimum(int a, int b, int c); + + int min = a; + + if(b < min) + min = b; + if(c < min) + min = c; + + return min; + + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_task_phase.svh b/test_regress/t/t_uvm/base/uvm_task_phase.svh new file mode 100644 index 0000000000..2cfcda8471 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_task_phase.svh @@ -0,0 +1,152 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2013-2015 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_task_phase +// +//------------------------------------------------------------------------------ +// Base class for all task phases. +// It forks a call to +// for each component in the hierarchy. +// +// The completion of the task does not imply, nor is it required for, +// the end of phase. Once the phase completes, any remaining forked +// threads are forcibly and immediately killed. +// +// By default, the way for a task phase to extend over time is if there is +// at least one component that raises an objection. +//| class my_comp extends uvm_component; +//| task main_phase(uvm_phase phase); +//| phase.raise_objection(this, "Applying stimulus") +//| ... +//| phase.drop_objection(this, "Applied enough stimulus") +//| endtask +//| endclass +// +// +// There is however one scenario wherein time advances within a task-based phase +// without any objections to the phase being raised. If two (or more) phases +// share a common successor, such as the and the +// sharing the as a successor, +// then phase advancement is delayed until all predecessors of the common +// successor are ready to proceed. Because of this, it is possible for time to +// advance between and +// of a task phase without any participants in the phase raising an objection. +// + +// @uvm-ieee 1800.2-2017 auto 9.6.1 +virtual class uvm_task_phase extends uvm_phase; + + + + // @uvm-ieee 1800.2-2017 auto 9.6.2.1 + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.6.2.2 + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + phase.m_num_procs_not_yet_returned = 0; + m_traverse(comp, phase, state); + endfunction + + function void m_traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain =phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + uvm_sequencer_base seqr; + + if (comp.get_first_child(name)) + do + m_traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + + if (m_phase_trace) + `uvm_info("PH_TRACE",$sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", + phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), + UVM_DEBUG) + + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + if ($cast(seqr, comp)) + seqr.start_phase_sequence(phase); + end + UVM_PHASE_EXECUTING: begin + uvm_phase ph = this; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + if ($cast(seqr, comp)) + seqr.stop_phase_sequence(phase); + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + `uvm_fatal("PH_BADEXEC","task phase traverse internal error") + endcase + end + + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.6.2.3 + virtual function void execute(uvm_component comp, + uvm_phase phase); + + fork + begin + process proc; + + // reseed this process for random stability + proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + + phase.m_num_procs_not_yet_returned++; + + exec_task(comp,phase); + + phase.m_num_procs_not_yet_returned--; + + end + join_none + + endfunction +endclass diff --git a/test_regress/t/t_uvm/base/uvm_text_tr_database.svh b/test_regress/t/t_uvm/base/uvm_text_tr_database.svh new file mode 100644 index 0000000000..fcd591460e --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_text_tr_database.svh @@ -0,0 +1,207 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// File -- NODOCS -- Transaction Recording Databases +// +// The UVM "Transaction Recording Database" classes are an abstract representation +// of the backend tool which is recording information for the user. Usually this +// tool would be dumping information such that it can be viewed with the ~waves~ +// of the DUT. +// + +typedef class uvm_recorder; +typedef class uvm_tr_stream; +typedef class uvm_link_base; +typedef class uvm_simple_lock_dap; +typedef class uvm_text_tr_stream; + + + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_text_tr_database +// +// The ~uvm_text_tr_database~ is the default implementation for the +// . It provides the ability to store recording information +// into a textual log file. +// +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + +class uvm_text_tr_database extends uvm_tr_database; + + // Variable- m_filename_dap + // Data Access Protected Filename + local uvm_simple_lock_dap#(string) m_filename_dap; + + // Variable- m_file + UVM_FILE m_file; + + `uvm_object_utils(uvm_text_tr_database) + + // Function: new + // Constructor + // + // Parameters: + // name - Instance name + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + function new(string name="unnamed-uvm_text_tr_database"); + super.new(name); + + m_filename_dap = new("filename_dap"); + m_filename_dap.set("tr_db.log"); + endfunction : new + + // Group: Implementation Agnostic API + + // Function: do_open_db + // Open the backend connection to the database. + // + // Text-Backend implementation of . + // + // The text-backend will open a text file to dump all records in to. The name + // of this text file is controlled via . + // + // This will also lock the ~file_name~, so that it cannot be + // modified while the connection is open. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + + protected virtual function bit do_open_db(); + if (m_file == 0) begin + m_file = $fopen(m_filename_dap.get(), "a+"); + if (m_file != 0) + m_filename_dap.lock(); + end + return (m_file != 0); + endfunction : do_open_db + + // Function: do_close_db + // Close the backend connection to the database. + // + // Text-Backend implementation of . + // + // The text-backend will close the text file used to dump all records in to, + // if it is currently opened. + // + // This unlocks the ~file_name~, allowing it to be modified again. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function bit do_close_db(); + if (m_file != 0) begin + fork // Needed because $fclose is a task + $fclose(m_file); + join_none + m_filename_dap.unlock(); + end + return 1; + endfunction : do_close_db + + // Function: do_open_stream + // Provides a reference to a ~stream~ within the + // database. + // + // Text-Backend implementation of + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function uvm_tr_stream do_open_stream(string name, + string scope, + string type_name); +`ifdef VERILATOR + uvm_text_tr_stream m_stream = uvm_text_tr_stream::type_id_create(name); +`else + uvm_text_tr_stream m_stream = uvm_text_tr_stream::type_id::create(name); +`endif + return m_stream; + endfunction : do_open_stream + + // Function: do_establish_link + // Establishes a ~link~ between two elements in the database + // + // Text-Backend implementation of . + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function void do_establish_link(uvm_link_base link); + uvm_recorder r_lhs, r_rhs; + uvm_object lhs = link.get_lhs(); + uvm_object rhs = link.get_rhs(); + + void'($cast(r_lhs, lhs)); + void'($cast(r_rhs, rhs)); + + if ((r_lhs == null) || + (r_rhs == null)) + return; + else begin + uvm_parent_child_link pc_link; + uvm_related_link re_link; + if ($cast(pc_link, link)) begin + $fdisplay(m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", + $time, + r_lhs.get_handle(), + r_rhs.get_handle(), + "child"); + + end + else if ($cast(re_link, link)) begin + $fdisplay(m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", + $time, + r_lhs.get_handle(), + r_rhs.get_handle(), + ""); + + end + end + endfunction : do_establish_link + + // Group: Implementation Specific API + + // Function: set_file_name + // Sets the file name which will be used for output. + // + // The ~set_file_name~ method can only be called prior to ~open_db~. + // + // By default, the database will use a file named "tr_db.log". + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + function void set_file_name(string filename); + if (filename == "") begin + `uvm_warning("UVM/TXT_DB/EMPTY_NAME", + "Ignoring attempt to set file name to ''!") + return; + end + + if (!m_filename_dap.try_set(filename)) begin + `uvm_warning("UVM/TXT_DB/SET_AFTER_OPEN", + "Ignoring attempt to change file name after opening the db!") + return; + end + endfunction : set_file_name + + +endclass : uvm_text_tr_database diff --git a/test_regress/t/t_uvm/base/uvm_text_tr_stream.svh b/test_regress/t/t_uvm/base/uvm_text_tr_stream.svh new file mode 100644 index 0000000000..1291022911 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_text_tr_stream.svh @@ -0,0 +1,125 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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: uvm_text_tr_stream +// +// The ~uvm_text_tr_stream~ is the default stream implementation for the +// . +// +// +// @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + +class uvm_text_tr_stream extends uvm_tr_stream; + + // Variable- m_text_db + // Internal reference to the text-based backend + local uvm_text_tr_database m_text_db; + + `uvm_object_utils_begin(uvm_text_tr_stream) + `uvm_object_utils_end + + // Function: new + // Constructor + // + // Parameters: + // name - Instance name + function new(string name="unnamed-uvm_text_tr_stream"); + super.new(name); + endfunction : new + + // Group: Implementation Agnostic API + + // Function: do_open + // Callback triggered via . + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function void do_open(uvm_tr_database db, + string scope, + string stream_type_name); + $cast(m_text_db, db); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " CREATE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + stream_type_name, + scope, + this.get_handle()); + endfunction : do_open + + // Function: do_close + // Callback triggered via . + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function void do_close(); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " CLOSE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + this.get_stream_type_name(), + this.get_scope(), + this.get_handle()); + endfunction : do_close + + // Function: do_free + // Callback triggered via . + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function void do_free(); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " FREE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + this.get_stream_type_name(), + this.get_scope(), + this.get_handle()); + m_text_db = null; + return; + endfunction : do_free + + // Function: do_open_recorder + // Marks the beginning of a new record in the stream + // + // Text-backend specific implementation. + // + // @uvm-accellera The details of this API are specific to the Accellera implementation, and are not being considered for contribution to 1800.2 + protected virtual function uvm_recorder do_open_recorder(string name, + time open_time, + string type_name); + if (m_text_db.open_db()) begin +`ifdef VERILATOR + return uvm_text_recorder::type_id_create(name); +`else + return uvm_text_recorder::type_id::create(name); +`endif + end + + return null; + endfunction : do_open_recorder + +endclass : uvm_text_tr_stream diff --git a/test_regress/t/t_uvm/base/uvm_topdown_phase.svh b/test_regress/t/t_uvm/base/uvm_topdown_phase.svh new file mode 100644 index 0000000000..6073f30103 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_topdown_phase.svh @@ -0,0 +1,109 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2015 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_topdown_phase +// +//------------------------------------------------------------------------------ +// Virtual base class for function phases that operate top-down. +// The pure virtual function execute() is called for each component. +// +// A top-down function phase completes when the method +// has been called and returned on all applicable components +// in the hierarchy. + +// @uvm-ieee 1800.2-2017 auto 9.7.1 +virtual class uvm_topdown_phase extends uvm_phase; + + + + // @uvm-ieee 1800.2-2017 auto 9.7.2.1 + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.7.2.2 + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain = phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + + if (m_phase_trace) + `uvm_info("PH_TRACE",$sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", + phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), + UVM_DEBUG) + + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + end + UVM_PHASE_EXECUTING: begin + if (!(phase.get_name() == "build" && comp.m_build_done)) begin + uvm_phase ph = this; + comp.m_phasing_active++; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + comp.m_phasing_active--; + end + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + `uvm_fatal("PH_BADEXEC","topdown phase traverse internal error") + endcase + end + if(comp.get_first_child(name)) + do + traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 9.7.2.3 + virtual function void execute(uvm_component comp, + uvm_phase phase); + // reseed this process for random stability + process proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + + comp.m_current_phase = phase; + exec_func(comp,phase); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_tr_database.svh b/test_regress/t/t_uvm/base/uvm_tr_database.svh new file mode 100644 index 0000000000..de143f11e6 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_tr_database.svh @@ -0,0 +1,229 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// File -- NODOCS -- Transaction Recording Databases +// +// The UVM "Transaction Recording Database" classes are an abstract representation +// of the backend tool which is recording information for the user. Usually this +// tool would be dumping information such that it can be viewed with the ~waves~ +// of the DUT. +// + +typedef class uvm_recorder; +typedef class uvm_tr_stream; +typedef class uvm_link_base; + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_tr_database +// +// The ~uvm_tr_database~ class is intended to hide the underlying database implementation +// from the end user, as these details are often vendor or tool-specific. +// +// The ~uvm_tr_database~ class is pure virtual, and must be extended with an +// implementation. A default text-based implementation is provided via the +// class. +// + +// @uvm-ieee 1800.2-2017 auto 7.1.1 +virtual class uvm_tr_database extends uvm_object; + + // Variable- m_is_opened + // Tracks the opened state of the database + local bit m_is_opened; + + // Variable- m_streams + // Used for tracking streams which are between the open and closed states + local bit m_streams[uvm_tr_stream]; + + + // @uvm-ieee 1800.2-2017 auto 7.1.2 + function new(string name="unnamed-uvm_tr_database"); + super.new(name); + endfunction : new + + // Group -- NODOCS -- Database API + + + // @uvm-ieee 1800.2-2017 auto 7.1.3.1 + function bit open_db(); + if (!m_is_opened) + m_is_opened = do_open_db(); + return m_is_opened; + endfunction : open_db + + + // @uvm-ieee 1800.2-2017 auto 7.1.3.2 + function bit close_db(); + if (m_is_opened) begin + if (do_close_db()) + m_is_opened = 0; + end + return (m_is_opened == 0); + endfunction : close_db + + + // @uvm-ieee 1800.2-2017 auto 7.1.3.3 + function bit is_open(); + return m_is_opened; + endfunction : is_open + + // Group -- NODOCS -- Stream API + + + // @uvm-ieee 1800.2-2017 auto 7.1.4.1 + function uvm_tr_stream open_stream(string name, + string scope="", + string type_name=""); + if (!open_db()) begin + return null; + end + else begin + process p = process::self(); + string s; + + if (p != null) + s = p.get_randstate(); + + open_stream = do_open_stream(name, scope, type_name); + + + if (open_stream != null) begin + m_streams[open_stream] = 1; + open_stream.m_do_open(this, scope, type_name); + end + + if (p != null) + p.set_randstate(s); + + end + endfunction : open_stream + + // Function- m_free_stream + // Removes stream from the internal array + function void m_free_stream(uvm_tr_stream stream); + if (m_streams.exists(stream)) + m_streams.delete(stream); + endfunction : m_free_stream + + + // @uvm-ieee 1800.2-2017 auto 7.1.4.2 + function unsigned get_streams(ref uvm_tr_stream q[$]); + // Clear out the queue first... + q.delete(); + // Then fill in the values + foreach (m_streams[idx]) + q.push_back(idx); + // Finally, return the size of the queue + return q.size(); + endfunction : get_streams + + // Group -- NODOCS -- Link API + + + // @uvm-ieee 1800.2-2017 auto 7.1.5 + function void establish_link(uvm_link_base link); + uvm_tr_stream s_lhs, s_rhs; + uvm_recorder r_lhs, r_rhs; + uvm_object lhs = link.get_lhs(); + uvm_object rhs = link.get_rhs(); + uvm_tr_database db; + + if (lhs == null) begin + `uvm_warning("UVM/TR_DB/BAD_LINK", + "left hand side '' is not supported in links for 'uvm_tr_database'") + return; + end + if (rhs == null) begin + `uvm_warning("UVM/TR_DB/BAD_LINK", + "right hand side '' is not supported in links for 'uvm_tr_database'") + return; + end + + if (!$cast(s_lhs, lhs) && + !$cast(r_lhs, lhs)) begin + `uvm_warning("UVM/TR_DB/BAD_LINK", + $sformatf("left hand side of type '%s' not supported in links for 'uvm_tr_database'", + lhs.get_type_name())) + return; + end + if (!$cast(s_rhs, rhs) && + !$cast(r_rhs, rhs)) begin + `uvm_warning("UVM/TR_DB/BAD_LINK", + $sformatf("right hand side of type '%s' not supported in links for 'uvm_record_datbasae'", + rhs.get_type_name())) + return; + end + + if (r_lhs != null) begin + s_lhs = r_lhs.get_stream(); + end + if (r_rhs != null) begin + s_rhs = r_rhs.get_stream(); + end + + if ((s_lhs != null) && (s_lhs.get_db() != this)) begin + db = s_lhs.get_db(); + `uvm_warning("UVM/TR_DB/BAD_LINK", + $sformatf("attempt to link stream from '%s' into '%s'", + db.get_name(), this.get_name())) + return; + end + if ((s_rhs != null) && (s_rhs.get_db() != this)) begin + db = s_rhs.get_db(); + `uvm_warning("UVM/TR_DB/BAD_LINK", + $sformatf("attempt to link stream from '%s' into '%s'", + db.get_name(), this.get_name())) + return; + end + + do_establish_link(link); + endfunction : establish_link + + // Group -- NODOCS -- Implementation Agnostic API + // + + + // @uvm-ieee 1800.2-2017 auto 7.1.6.1 + pure virtual protected function bit do_open_db(); + + + // @uvm-ieee 1800.2-2017 auto 7.1.6.2 + pure virtual protected function bit do_close_db(); + + + // @uvm-ieee 1800.2-2017 auto 7.1.6.3 + pure virtual protected function uvm_tr_stream do_open_stream(string name, + string scope, + string type_name); + + + // @uvm-ieee 1800.2-2017 auto 7.1.6.4 + pure virtual protected function void do_establish_link(uvm_link_base link); + +endclass : uvm_tr_database + diff --git a/test_regress/t/t_uvm/base/uvm_tr_stream.svh b/test_regress/t/t_uvm/base/uvm_tr_stream.svh new file mode 100644 index 0000000000..6aeefb9ab4 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_tr_stream.svh @@ -0,0 +1,392 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// File -- NODOCS -- Transaction Recording Streams +// + +// class- m_uvm_tr_stream_cfg +// Undocumented helper class for storing stream +// initialization values. +class m_uvm_tr_stream_cfg; + uvm_tr_database db; + string scope; + string stream_type_name; +endclass : m_uvm_tr_stream_cfg + +typedef class uvm_set_before_get_dap; +typedef class uvm_text_recorder; + + +// @uvm-ieee 1800.2-2017 auto 7.2.1 +virtual class uvm_tr_stream extends uvm_object; + + // Variable- m_cfg_dap + // Data access protected reference to the DB + local uvm_set_before_get_dap#(m_uvm_tr_stream_cfg) m_cfg_dap; + + // Variable- m_records + // Active records in the stream (active == open or closed) + local bit m_records[uvm_recorder]; + + // Variable- m_warn_null_cfg + // Used to limit the number of warnings + local bit m_warn_null_cfg; + + // Variable- m_is_opened + // Used to indicate stream is open + local bit m_is_opened; + + // Variable- m_is_closed + // Used to indicate stream is closed + local bit m_is_closed; + + // !m_is_opened && !m_is_closed == m_is_freed + + + // @uvm-ieee 1800.2-2017 auto 7.2.2 + function new(string name="unnamed-uvm_tr_stream"); + super.new(name); + m_cfg_dap = new("cfg_dap"); + endfunction : new + + // Variable- m_ids_by_stream + // An associative array of int, indexed by uvm_tr_streams. This + // provides a unique 'id' or 'handle' for each stream, which can be + // used to identify the stream. + // + // By default, neither ~m_ids_by_stream~ or ~m_streams_by_id~ are + // used. Streams are only placed in the arrays when the user + // attempts to determine the id for a stream. + local static int m_ids_by_stream[uvm_tr_stream]; + + // Group -- NODOCS -- Configuration API + + + // @uvm-ieee 1800.2-2017 auto 7.2.3.1 + function uvm_tr_database get_db(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + `uvm_warning("UVM/REC_STR/NO_CFG", + $sformatf("attempt to retrieve DB from '%s' before it was set!", + get_name())) + m_warn_null_cfg = 0; + return null; + end + return m_cfg.db; + endfunction : get_db + + + // @uvm-ieee 1800.2-2017 auto 7.2.3.2 + function string get_scope(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + `uvm_warning("UVM/REC_STR/NO_CFG", + $sformatf("attempt to retrieve scope from '%s' before it was set!", + get_name())) + m_warn_null_cfg = 0; + return ""; + end + return m_cfg.scope; + endfunction : get_scope + + + // @uvm-ieee 1800.2-2017 auto 7.2.3.3 + function string get_stream_type_name(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + `uvm_warning("UVM/REC_STR/NO_CFG", + $sformatf("attempt to retrieve STREAM_TYPE_NAME from '%s' before it was set!", + get_name())) + m_warn_null_cfg = 0; + return ""; + end + return m_cfg.stream_type_name; + endfunction : get_stream_type_name + + // Group -- NODOCS -- Stream API + // + // Once a stream has been opened via , the user + // can ~close~ the stream. + // + // Due to the fact that many database implementations will require crossing + // a language boundary, an additional step of ~freeing~ the stream is required. + // + // A ~link~ can be established within the database any time between "Open" and + // "Free", however it is illegal to establish a link after "Freeing" the stream. + // + + + // @uvm-ieee 1800.2-2017 auto 7.2.4.1 + function void close(); + if (!is_open()) + return; + + do_close(); + + foreach (m_records[idx]) + if (idx.is_open()) + idx.close(); + + m_is_opened = 0; + m_is_closed = 1; + endfunction : close + + + // @uvm-ieee 1800.2-2017 auto 7.2.4.2 + function void free(); + process p; + string s; + uvm_tr_database db; + if (!is_open() && !is_closed()) + return; + + if (is_open()) + close(); + + do_free(); + + foreach (m_records[idx]) + idx.free(); + + // Clear out internal state + db = get_db(); + m_is_closed = 0; + p = process::self(); + if(p != null) + s = p.get_randstate(); + m_cfg_dap = new("cfg_dap"); + if(p != null) + p.set_randstate(s); + m_warn_null_cfg = 1; + if (m_ids_by_stream.exists(this)) + m_free_id(m_ids_by_stream[this]); + + // Clear out DB state + if (db != null) + db.m_free_stream(this); + endfunction : free + + // Function- m_do_open + // Initializes the state of the stream + // + // Parameters- + // db - Database which the stream belongs to + // scope - Optional scope + // stream_type_name - Optional type name for the stream + // + // This method will trigger a call. + // + // An error will be asserted if- + // - m_do_open is called more than once without the stream + // being ~freed~ between. + // - m_do_open is passed a ~null~ db + function void m_do_open(uvm_tr_database db, + string scope="", + string stream_type_name=""); + + m_uvm_tr_stream_cfg m_cfg; + uvm_tr_database m_db; + if (db == null) begin + `uvm_error("UVM/REC_STR/NULL_DB", + $sformatf("Illegal attempt to set DB for '%s' to ''", + this.get_full_name())) + return; + end + + if (m_cfg_dap.try_get(m_cfg)) begin + `uvm_error("UVM/REC_STR/RE_CFG", + $sformatf("Illegal attempt to re-open '%s'", + this.get_full_name())) + end + else begin + // Never set before + m_cfg = new(); + m_cfg.db = db; + m_cfg.scope = scope; + m_cfg.stream_type_name = stream_type_name; + m_cfg_dap.set(m_cfg); + m_is_opened = 1; + + do_open(db, scope, stream_type_name); + end + + endfunction : m_do_open + + + // @uvm-ieee 1800.2-2017 auto 7.2.4.3 + function bit is_open(); + return m_is_opened; + endfunction : is_open + + + // @uvm-ieee 1800.2-2017 auto 7.2.4.4 + function bit is_closed(); + return m_is_closed; + endfunction : is_closed + + // Group -- NODOCS -- Transaction Recorder API + // + // New recorders can be opened prior to the stream being ~closed~. + // + // Once a stream has been closed, requests to open a new recorder + // will be ignored ( will return ~null~). + // + + + // @uvm-ieee 1800.2-2017 auto 7.2.5.1 + function uvm_recorder open_recorder(string name, + time open_time = 0, + string type_name=""); + time m_time = (open_time == 0) ? $time : open_time; + + // Check to make sure we're open + if (!is_open()) + return null; + else begin + process p = process::self(); + string s; + + if (p != null) + s = p.get_randstate(); + + open_recorder = do_open_recorder(name, + m_time, + type_name); + + + + if (open_recorder != null) begin + m_records[open_recorder] = 1; + open_recorder.m_do_open(this, m_time, type_name); + end + if (p != null) + p.set_randstate(s); + end + endfunction : open_recorder + + // Function- m_free_recorder + // Removes recorder from the internal array + function void m_free_recorder(uvm_recorder recorder); + if (m_records.exists(recorder)) + m_records.delete(recorder); + endfunction : m_free_recorder + + + // @uvm-ieee 1800.2-2017 auto 7.2.5.2 + function unsigned get_recorders(ref uvm_recorder q[$]); + // Clear out the queue first... + q.delete(); + // Fill in the values + foreach (m_records[idx]) + q.push_back(idx); + // Finally return the size of the queue + return q.size(); + endfunction : get_recorders + + // Group -- NODOCS -- Handles + + // Variable- m_streams_by_id + // A corollary to ~m_ids_by_stream~, this indexes the streams by their + // unique ids. + local static uvm_tr_stream m_streams_by_id[int]; + + + // @uvm-ieee 1800.2-2017 auto 7.2.6.1 + function int get_handle(); + if (!is_open() && !is_closed()) begin + return 0; + end + else begin + int handle = get_inst_id(); + + // Check for the weird case where our handle changed. + if (m_ids_by_stream.exists(this) && m_ids_by_stream[this] != handle) + m_streams_by_id.delete(m_ids_by_stream[this]); + + m_streams_by_id[handle] = this; + m_ids_by_stream[this] = handle; + + return handle; + end + endfunction : get_handle + + // @uvm-ieee 1800.2-2017 auto 7.2.6.2 + static function uvm_tr_stream get_stream_from_handle(int id); + if (id == 0) + return null; + + if ($isunknown(id) || !m_streams_by_id.exists(id)) + return null; + + return m_streams_by_id[id]; + endfunction : get_stream_from_handle + + // Function- m_free_id + // Frees the id/stream link (memory cleanup) + // + static function void m_free_id(int id); + uvm_tr_stream stream; + if (!$isunknown(id) && m_streams_by_id.exists(id)) + stream = m_streams_by_id[id]; + + if (stream != null) begin + m_streams_by_id.delete(id); + m_ids_by_stream.delete(stream); + end + endfunction : m_free_id + + // Group -- NODOCS -- Implementation Agnostic API + // + + + // @uvm-ieee 1800.2-2017 auto 7.2.7.1 + protected virtual function void do_open(uvm_tr_database db, + string scope, + string stream_type_name); + endfunction : do_open + + + // @uvm-ieee 1800.2-2017 auto 7.2.7.2 + protected virtual function void do_close(); + endfunction : do_close + + + // @uvm-ieee 1800.2-2017 auto 7.2.7.3 + protected virtual function void do_free(); + endfunction : do_free + + + // @uvm-ieee 1800.2-2017 auto 7.2.7.4 + protected virtual function uvm_recorder do_open_recorder(string name, + time open_time, + string type_name); + return null; + endfunction : do_open_recorder + +endclass : uvm_tr_stream + diff --git a/test_regress/t/t_uvm/base/uvm_transaction.svh b/test_regress/t/t_uvm/base/uvm_transaction.svh new file mode 100644 index 0000000000..e64e35aef7 --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_transaction.svh @@ -0,0 +1,816 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014-2017 Cisco Systems, 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. +//----------------------------------------------------------------------------- + +typedef class uvm_event; +typedef class uvm_event_pool; +typedef class uvm_component; +typedef class uvm_parent_child_link; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_transaction +// +// The uvm_transaction class is the root base class for UVM transactions. +// Inheriting all the methods of , uvm_transaction adds a timing and +// recording interface. +// +// This class provides timestamp properties, notification events, and transaction +// recording support. +// +// Use of this class as a base for user-defined transactions +// is deprecated. Its subtype, , shall be used as the +// base class for all user-defined transaction types. +// +// The intended use of this API is via a to call , +// , and during the course of +// sequence item execution. These methods in the component base class will +// call into the corresponding methods in this class to set the corresponding +// timestamps (~accept_time~, ~begin_time~, and ~end_time~), trigger the +// corresponding event ( and , and, if enabled, +// record the transaction contents to a vendor-specific transaction database. +// +// Note that get_next_item/item_done when called on a uvm_seq_item_pull_port +// will automatically trigger the begin_event and end_events via calls to begin_tr and end_tr. +// While convenient, it is generally the responsibility of drivers to mark a +// transaction's progress during execution. To allow the driver or layering sequence +// to control sequence item timestamps, events, and recording, you must call +// at the beginning +// of the driver's ~run_phase~ task. +// +// Users may also use the transaction's event pool, , +// to define custom events for the driver to trigger and the sequences to wait on. Any +// in-between events such as marking the beginning of the address and data +// phases of transaction execution could be implemented via the +// pool. +// +// In pipelined protocols, the driver may release a sequence (return from +// finish_item() or it's `uvm_do macro) before the item has been completed. +// If the driver uses the begin_tr/end_tr API in uvm_component, the sequence can +// wait on the item's to block until the item was fully executed, +// as in the following example. +// +//| task uvm_execute(item, ...); +//| // can use the `uvm_do macros as well +//| start_item(item); +//| item.randomize(); +//| finish_item(item); +//| item.end_event.wait_on(); +//| // get_response(rsp, item.get_transaction_id()); //if needed +//| endtask +//| +// +// A simple two-stage pipeline driver that can execute address and +// data phases concurrently might be implemented as follows: +// +//| task run(); +//| // this driver supports a two-deep pipeline +//| fork +//| do_item(); +//| do_item(); +//| join +//| endtask +//| +//| +//| task do_item(); +//| +//| forever begin +//| mbus_item req; +//| +//| lock.get(); +//| +//| seq_item_port.get(req); // Completes the sequencer-driver handshake +//| +//| accept_tr(req); +//| +//| // request bus, wait for grant, etc. +//| +//| begin_tr(req); +//| +//| // execute address phase +//| +//| // allows next transaction to begin address phase +//| lock.put(); +//| +//| // execute data phase +//| // (may trigger custom "data_phase" event here) +//| +//| end_tr(req); +//| +//| end +//| +//| endtask: do_item +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 5.4.1 +virtual class uvm_transaction extends uvm_object; + + // Function -- NODOCS -- new + // + // Creates a new transaction object. The name is the instance name of the + // transaction. If not supplied, then the object is unnamed. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.1 + extern function new (string name="", uvm_component initiator=null); + + + // Function -- NODOCS -- accept_tr + // + // Calling ~accept_tr~ indicates that the transaction item has been received by + // a consumer component. Typically a would call , + // which calls this method-- upon return from a ~get_next_item()~, ~get()~, or ~peek()~ + // call on its sequencer port, . + // + // With some + // protocols, the received item may not be started immediately after it is + // accepted. For example, a bus driver, having accepted a request transaction, + // may still have to wait for a bus grant before beginning to execute + // the request. + // + // This function performs the following actions: + // + // - The transaction's internal accept time is set to the current simulation + // time, or to accept_time if provided and non-zero. The ~accept_time~ may be + // any time, past or future. + // + // - The transaction's internal accept event is triggered. Any processes + // waiting on the this event will resume in the next delta cycle. + // + // - The method is called to allow for any post-accept + // action in derived classes. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.2 + extern function void accept_tr (time accept_time = 0); + + + // Function -- NODOCS -- do_accept_tr + // + // This user-definable callback is called by just before the accept + // event is triggered. Implementations should call ~super.do_accept_tr~ to + // ensure correct operation. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.3 + extern virtual protected function void do_accept_tr (); + + + // Function -- NODOCS -- begin_tr + // + // This function indicates that the transaction has been started and is not + // the child of another transaction. Generally, a consumer component begins + // execution of a transactions it receives. + // + // Typically a would call , which + // calls this method, before actual execution of a sequence item transaction. + // Sequence items received by a driver are always a child of a parent sequence. + // In this case, begin_tr obtains the parent handle and delegates to . + // + // See for more information on how the + // begin-time might differ from when the transaction item was received. + // + // This function performs the following actions: + // + // - The transaction's internal start time is set to the current simulation + // time, or to begin_time if provided and non-zero. The begin_time may be + // any time, past or future, but should not be less than the accept time. + // + // - If recording is enabled, then a new database-transaction is started with + // the same begin time as above. + // + // - The method is called to allow for any post-begin action in + // derived classes. + // + // - The transaction's internal begin event is triggered. Any processes + // waiting on this event will resume in the next delta cycle. + // + // The return value is a transaction handle, which is valid (non-zero) only if + // recording is enabled. The meaning of the handle is implementation specific. + + + // @uvm-ieee 1800.2-2017 auto 5.4.2.4 + extern function int begin_tr (time begin_time = 0); + + + // Function -- NODOCS -- begin_child_tr + // + // This function indicates that the transaction has been started as a child of + // a parent transaction given by ~parent_handle~. Generally, a consumer + // component calls this method via to indicate + // the actual start of execution of this transaction. + // + // The parent handle is obtained by a previous call to begin_tr or + // begin_child_tr. If the parent_handle is invalid (=0), then this function + // behaves the same as . + // + // This function performs the following actions: + // + // - The transaction's internal start time is set to the current simulation + // time, or to begin_time if provided and non-zero. The begin_time may be + // any time, past or future, but should not be less than the accept time. + // + // - If recording is enabled, then a new database-transaction is started with + // the same begin time as above. The inherited method + // is then called, which records the current property values to this new + // transaction. Finally, the newly started transaction is linked to the + // parent transaction given by parent_handle. + // + // - The method is called to allow for any post-begin + // action in derived classes. + // + // - The transaction's internal begin event is triggered. Any processes + // waiting on this event will resume in the next delta cycle. + // + // The return value is a transaction handle, which is valid (non-zero) only if + // recording is enabled. The meaning of the handle is implementation specific. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.5 + extern function int begin_child_tr (time begin_time = 0, + int parent_handle = 0); + + + // Function -- NODOCS -- do_begin_tr + // + // This user-definable callback is called by and just + // before the begin event is triggered. Implementations should call + // ~super.do_begin_tr~ to ensure correct operation. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.6 + extern virtual protected function void do_begin_tr (); + + + // Function -- NODOCS -- end_tr + // + // This function indicates that the transaction execution has ended. + // Generally, a consumer component ends execution of the transactions it + // receives. + // + // You must have previously called or for this + // call to be successful. + // + // Typically a would call , which + // calls this method, upon completion of a sequence item transaction. + // Sequence items received by a driver are always a child of a parent sequence. + // In this case, begin_tr obtain the parent handle and delegate to . + // + // This function performs the following actions: + // + // - The transaction's internal end time is set to the current simulation + // time, or to ~end_time~ if provided and non-zero. The ~end_time~ may be any + // time, past or future, but should not be less than the begin time. + // + // - If recording is enabled and a database-transaction is currently active, + // then the record method inherited from uvm_object is called, which records + // the final property values. The transaction is then ended. If ~free_handle~ + // is set, the transaction is released and can no longer be linked to (if + // supported by the implementation). + // + // - The method is called to allow for any post-end + // action in derived classes. + // + // - The transaction's internal end event is triggered. Any processes waiting + // on this event will resume in the next delta cycle. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.7 + extern function void end_tr (time end_time=0, bit free_handle=1); + + + // Function -- NODOCS -- do_end_tr + // + // This user-definable callback is called by just before the end event + // is triggered. Implementations should call ~super.do_end_tr~ to ensure correct + // operation. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.8 + extern virtual protected function void do_end_tr (); + + + // Function -- NODOCS -- get_tr_handle + // + // Returns the handle associated with the transaction, as set by a previous + // call to or with transaction recording enabled. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.9 + extern function int get_tr_handle (); + + + // Function -- NODOCS -- disable_recording + // + // Turns off recording for the transaction stream. This method does not + // effect a 's recording streams. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.11 + extern function void disable_recording (); + + + // @uvm-ieee 1800.2-2017 auto 5.4.2.10 + extern function void enable_recording (uvm_tr_stream stream); + + // Function -- NODOCS -- is_recording_enabled + // + // Returns 1 if recording is currently on, 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.12 + extern function bit is_recording_enabled(); + + + // Function -- NODOCS -- is_active + // + // Returns 1 if the transaction has been started but has not yet been ended. + // Returns 0 if the transaction has not been started. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.13 + extern function bit is_active (); + + + // Function -- NODOCS -- get_event_pool + // + // Returns the event pool associated with this transaction. + // + // By default, the event pool contains the events: begin, accept, and end. + // Events can also be added by derivative objects. An event pool is a + // specialization of , e.g. a ~uvm_pool#(uvm_event)~. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.14 + extern function uvm_event_pool get_event_pool (); + + + // Function -- NODOCS -- set_initiator + // + // Sets initiator as the initiator of this transaction. + // + // The initiator can be the component that produces the transaction. It can + // also be the component that started the transaction. This or any other + // usage is up to the transaction designer. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.15 + extern function void set_initiator (uvm_component initiator); + + + // Function -- NODOCS -- get_initiator + // + // Returns the component that produced or started the transaction, as set by + // a previous call to set_initiator. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.16 + extern function uvm_component get_initiator (); + + + // Function -- NODOCS -- get_accept_time + + // @uvm-ieee 1800.2-2017 auto 5.4.2.17 + extern function time get_accept_time (); + + // Function -- NODOCS -- get_begin_time + + // @uvm-ieee 1800.2-2017 auto 5.4.2.17 + extern function time get_begin_time (); + + // Function -- NODOCS -- get_end_time + // + // Returns the time at which this transaction was accepted, begun, or ended, + // as by a previous call to , , , or . + + // @uvm-ieee 1800.2-2017 auto 5.4.2.17 + extern function time get_end_time (); + + + // Function -- NODOCS -- set_transaction_id + // + // Sets this transaction's numeric identifier to id. If not set via this + // method, the transaction ID defaults to -1. + // + // When using sequences to generate stimulus, the transaction ID is used along + // with the sequence ID to route responses in sequencers and to correlate + // responses to requests. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.18 + extern function void set_transaction_id(int id); + + + // Function -- NODOCS -- get_transaction_id + // + // Returns this transaction's numeric identifier, which is -1 if not set + // explicitly by ~set_transaction_id~. + // + // When using a to generate stimulus, the transaction + // ID is used along + // with the sequence ID to route responses in sequencers and to correlate + // responses to requests. + + // @uvm-ieee 1800.2-2017 auto 5.4.2.19 + extern function int get_transaction_id(); + + + // Variable -- NODOCS -- events + // + // The event pool instance for this transaction. This pool is used to track + // various milestones: by default, begin, accept, and end + +`ifdef UVM_ENABLE_DEPRECATED_API + const uvm_event_pool events = new("events"); +`else + const local uvm_event_pool events = new("events"); +`endif + + + // Variable -- NODOCS -- begin_event + // + // A ~uvm_event#(uvm_object)~ that is triggered when this transaction's actual execution on the + // bus begins, typically as a result of a driver calling . + // Processes that wait on this event will block until the transaction has + // begun. + // + // For more information, see the general discussion for . + // See for details on the event API. + // +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_event#(uvm_object) begin_event; +`endif + + // Variable -- NODOCS -- end_event + // + // A ~uvm_event#(uvm_object)~ that is triggered when this transaction's actual execution on + // the bus ends, typically as a result of a driver calling . + // Processes that wait on this event will block until the transaction has + // ended. + // + // For more information, see the general discussion for . + // See for details on the event API. + // + //| virtual task my_sequence::body(); + //| ... + //| start_item(item); \ + //| item.randomize(); } `uvm_do(item) + //| finish_item(item); / + //| // return from finish item does not always mean item is completed + //| item.end_event.wait_on(); + //| ... + // +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_event#(uvm_object) end_event; +`endif + + //---------------------------------------------------------------------------- + // + // Internal methods properties; do not use directly + // + //---------------------------------------------------------------------------- + + //Override data control methods for internal properties + extern virtual function void do_print (uvm_printer printer); + extern virtual function void do_record (uvm_recorder recorder); + extern virtual function void do_copy (uvm_object rhs); + + + extern protected function int m_begin_tr (time begin_time=0, + int parent_handle=0); + + local int m_transaction_id = -1; + + local time begin_time=-1; + local time end_time=-1; + local time accept_time=-1; + + local uvm_component initiator; + local uvm_tr_stream stream_handle; + local uvm_recorder tr_recorder; + +endclass + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + + +// new +// --- + +function uvm_transaction::new (string name="", + uvm_component initiator = null); + + super.new(name); + this.initiator = initiator; + m_transaction_id = -1; +`ifdef UVM_ENABLE_DEPRECATED_API + begin_event = events.get("begin"); + end_event = events.get("end"); +`endif +endfunction // uvm_transaction + + +// set_transaction_id +function void uvm_transaction::set_transaction_id(int id); + m_transaction_id = id; +endfunction + +// get_transaction_id +function int uvm_transaction::get_transaction_id(); + return (m_transaction_id); +endfunction + +// set_initiator +// ------------ + +function void uvm_transaction::set_initiator(uvm_component initiator); + this.initiator = initiator; +endfunction + +// get_initiator +// ------------ + +function uvm_component uvm_transaction::get_initiator(); + return initiator; +endfunction + +// get_event_pool +// -------------- + +function uvm_event_pool uvm_transaction::get_event_pool(); + return events; +endfunction + + +// is_active +// --------- + +function bit uvm_transaction::is_active(); + return (end_time == -1); +endfunction + + +// get_begin_time +// -------------- + +function time uvm_transaction::get_begin_time (); + return begin_time; +endfunction + + +// get_end_time +// ------------ + +function time uvm_transaction::get_end_time (); + return end_time; +endfunction + + +// get_accept_time +// --------------- + +function time uvm_transaction::get_accept_time (); + return accept_time; +endfunction + + +// do_accept_tr +// ------------- + +function void uvm_transaction::do_accept_tr(); + return; +endfunction + + +// do_begin_tr +// ------------ + +function void uvm_transaction::do_begin_tr(); + return; +endfunction + + +// do_end_tr +// ---------- + +function void uvm_transaction::do_end_tr(); + return; +endfunction + +// do_print +// -------- + +function void uvm_transaction::do_print (uvm_printer printer); + string str; + uvm_component tmp_initiator; //work around $swrite bug + super.do_print(printer); + if(accept_time != -1) + printer.print_time("accept_time", accept_time); + if(begin_time != -1) + printer.print_time("begin_time", begin_time); + if(end_time != -1) + printer.print_time("end_time", end_time); + if(initiator != null) begin + tmp_initiator = initiator; + $swrite(str,"@%0d", tmp_initiator.get_inst_id()); + printer.print_generic("initiator", initiator.get_type_name(), -1, str); + end +endfunction + +function void uvm_transaction::do_copy (uvm_object rhs); + uvm_transaction txn; + super.do_copy(rhs); + if(rhs == null) return; + if(!$cast(txn, rhs) ) return; + + accept_time = txn.accept_time; + begin_time = txn.begin_time; + end_time = txn.end_time; + initiator = txn.initiator; + stream_handle = txn.stream_handle; + tr_recorder = txn.tr_recorder; +endfunction + +// do_record +// --------- + +function void uvm_transaction::do_record (uvm_recorder recorder); + string s; + super.do_record(recorder); + if(accept_time != -1) + recorder.record_field("accept_time", accept_time, $bits(accept_time), UVM_TIME); + if(initiator != null) begin + uvm_recursion_policy_enum p = recorder.get_recursion_policy(); + recorder.set_recursion_policy(UVM_REFERENCE); + recorder.record_object("initiator", initiator); + recorder.set_recursion_policy(p); + end +endfunction + +// get_tr_handle +// --------- + +function int uvm_transaction::get_tr_handle (); + if (tr_recorder != null) + return tr_recorder.get_handle(); + else + return 0; +endfunction + + +// disable_recording +// ----------------- + +function void uvm_transaction::disable_recording (); + this.stream_handle = null; +endfunction + + +// enable_recording +// ---------------- + +function void uvm_transaction::enable_recording (uvm_tr_stream stream); + this.stream_handle = stream; +endfunction : enable_recording + +// is_recording_enabled +// -------------------- + +function bit uvm_transaction::is_recording_enabled (); + return (this.stream_handle != null); +endfunction + + +// accept_tr +// --------- + +function void uvm_transaction::accept_tr (time accept_time = 0); + uvm_event#(uvm_object) e; + + if(accept_time != 0) + this.accept_time = accept_time; + else + this.accept_time = $realtime; + + do_accept_tr(); + e = events.get("accept"); + + if(e!=null) + e.trigger(); +endfunction + +// begin_tr +// ----------- + +function int uvm_transaction::begin_tr (time begin_time=0); + return m_begin_tr(begin_time); +endfunction + +// begin_child_tr +// -------------- + +//Use a parent handle of zero to link to the parent after begin +function int uvm_transaction::begin_child_tr (time begin_time=0, + int parent_handle=0); + return m_begin_tr(begin_time, parent_handle); +endfunction + +// m_begin_tr +// ----------- + +function int uvm_transaction::m_begin_tr (time begin_time=0, + int parent_handle=0); + time tmp_time = (begin_time == 0) ? $realtime : begin_time; + uvm_recorder parent_recorder; + + if (parent_handle != 0) + parent_recorder = uvm_recorder::get_recorder_from_handle(parent_handle); + + // If we haven't ended the previous record, end it. + if (tr_recorder != null) + // Don't free the handle, someone else may be using it... + end_tr(tmp_time); + + // May want to establish predecessor/successor relation + // (don't free handle until then) + if(is_recording_enabled()) begin + uvm_tr_database db = stream_handle.get_db(); + + this.end_time = -1; + this.begin_time = tmp_time; + + if(parent_recorder == null) + tr_recorder = stream_handle.open_recorder(get_type_name(), + this.begin_time, + "Begin_No_Parent, Link"); + else begin + tr_recorder = stream_handle.open_recorder(get_type_name(), + this.begin_time, + "Begin_End, Link"); + + if (tr_recorder != null) + db.establish_link(uvm_parent_child_link::get_link(parent_recorder, tr_recorder)); + end + + if (tr_recorder != null) + m_begin_tr = tr_recorder.get_handle(); + else + m_begin_tr = 0; + end + else begin + tr_recorder = null; + this.end_time = -1; + this.begin_time = tmp_time; + + m_begin_tr = 0; + end + + do_begin_tr(); //execute callback before event trigger + + begin + uvm_event#(uvm_object) begin_event ; + begin_event = events.get("begin"); + begin_event.trigger(); + end + +endfunction + + +// end_tr +// ------ + +function void uvm_transaction::end_tr (time end_time=0, bit free_handle=1); + this.end_time = (end_time == 0) ? $realtime : end_time; + + do_end_tr(); // Callback prior to actual ending of transaction + + if(is_recording_enabled() && (tr_recorder != null)) begin + record(tr_recorder); + + tr_recorder.close(this.end_time); + + if(free_handle) + begin + // once freed, can no longer link to + tr_recorder.free(); + end + end // if (is_active()) + + tr_recorder = null; + + begin + uvm_event#(uvm_object) end_event ; + end_event = events.get("end") ; + end_event.trigger(); + end +endfunction diff --git a/test_regress/t/t_uvm/base/uvm_traversal.svh b/test_regress/t/t_uvm/base/uvm_traversal.svh new file mode 100644 index 0000000000..0255f9780b --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_traversal.svh @@ -0,0 +1,293 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_visitor #(NODE) +// +// The uvm_visitor class provides an abstract base class for a visitor. The visitor +// visits instances of type NODE. For general information regarding the visitor pattern +// see http://en.wikipedia.org/wiki/Visitor_pattern +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.1.1 +virtual class uvm_visitor#(type NODE=uvm_component) extends uvm_object; + function new (string name = ""); + super.new(name); + endfunction + + // Function -- NODOCS -- begin_v + // + // This method will be invoked by the visitor before the first NODE is visited + + // @uvm-ieee 1800.2-2017 auto F.5.1.2.1 + virtual function void begin_v(); endfunction + + // Function -- NODOCS -- end_v + // + // This method will be invoked by the visitor after the last NODE is visited + + // @uvm-ieee 1800.2-2017 auto F.5.1.2.2 + virtual function void end_v(); endfunction + + + // @uvm-ieee 1800.2-2017 auto F.5.1.2.3 + pure virtual function void visit(NODE node); +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_structure_proxy #(STRUCTURE) +// +// The uvm_structure_proxy is a wrapper and provides a set of elements +// of the STRUCTURE to the caller on demand. This is to decouple the retrieval of +// the STRUCTUREs subelements from the actual function being invoked on STRUCTURE +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.2.1 +virtual class uvm_structure_proxy#(type STRUCTURE=uvm_component) extends uvm_object; + // @uvm-ieee 1800.2-2017 auto F.5.2.2.1 + function new (string name = ""); + super.new(name); + endfunction + + // Function -- NODOCS -- get_immediate_children + // + // This method will be return in ~children~ a set of the direct subelements of ~s~ + + // @uvm-ieee 1800.2-2017 auto F.5.2.2.2 + pure virtual function void get_immediate_children(STRUCTURE s, ref STRUCTURE children[$]); +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_visitor_adapter #(STRUCTURE,uvm_visitor#(STRUCTURE)) +// +// The visitor adaptor traverses all nodes of the STRUCTURE and will invoke visitor.visit() on every node. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.3.1 +virtual class uvm_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends uvm_object; + // Function -- NODOCS -- accept() + // + // Calling this function will traverse through ~s~ (and every subnode of ~s~). For each node found + // ~v~.visit(node) will be invoked. The children of ~s~ are recursively determined + // by invoking ~p~.get_immediate_children().~invoke_begin_end~ determines whether the visitors begin/end functions + // should be invoked prior to traversal. + + // @uvm-ieee 1800.2-2017 auto F.5.3.2.2 + pure virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + + // @uvm-ieee 1800.2-2017 auto F.5.3.2.1 + function new (string name = ""); + super.new(name); + endfunction +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_top_down_visitor_adapter +// +// This uvm_top_down_visitor_adapter traverses the STRUCTURE ~s~ (and will invoke the visitor) in a hierarchical fashion. +// During traversal ~s~ will be visited before all subnodes of ~s~ will be visited. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.4.1 +class uvm_top_down_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + + // @uvm-ieee 1800.2-2017 auto F.5.4.2 + function new (string name = ""); + super.new(name); + endfunction + + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + + if(invoke_begin_end) + v.begin_v(); + + v.visit(s); + p.get_immediate_children(s, c); + + foreach(c[idx]) + accept(c[idx],v,p,0); + + if(invoke_begin_end) + v.end_v(); + + endfunction +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_bottom_up_visitor_adapter +// +// This uvm_bottom_up_visitor_adapter traverses the STRUCTURE ~s~ (and will invoke the visitor) in a hierarchical fashion. +// During traversal all children of node ~s~ will be visited ~s~ will be visited. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.5.1 +class uvm_bottom_up_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + + // @uvm-ieee 1800.2-2017 auto F.5.5.2 + function new (string name = ""); + super.new(name); + endfunction + + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + + if(invoke_begin_end) + v.begin_v(); + + p.get_immediate_children(s, c); + foreach(c[idx]) + accept(c[idx],v,p,0); + + v.visit(s); + + if(invoke_begin_end) + v.end_v(); + + endfunction +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_by_level_visitor_adapter +// +// This uvm_by_level_visitor_adapter traverses the STRUCTURE ~s~ (and will invoke the visitor) in a hierarchical fashion. +// During traversal will visit all direct children of ~s~ before all grand-children are visited. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.6.1 +class uvm_by_level_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + + // @uvm-ieee 1800.2-2017 auto F.5.6.2 + function new (string name = ""); + super.new(name); + endfunction + + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + c.push_back(s); + + if(invoke_begin_end) + v.begin_v(); + + while(c.size() > 0) begin + STRUCTURE q[$]; + foreach(c[idx]) begin + STRUCTURE t[$]; + + v.visit(c[idx]); + p.get_immediate_children(c[idx], t); + q = {q,t}; + end + c=q; + end + + if(invoke_begin_end) + v.end_v(); + endfunction +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_component_proxy +// +// The class is providing the proxy to extract the direct subcomponents of ~s~ +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto F.5.7.1 +class uvm_component_proxy extends uvm_structure_proxy#(uvm_component); + virtual function void get_immediate_children(STRUCTURE s, ref STRUCTURE children[$]); + s.get_children(children); + endfunction + + // @uvm-ieee 1800.2-2017 auto F.5.7.2 + function new (string name = ""); + super.new(name); + endfunction +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_component_name_check_visitor +// +// This specialized visitor analyze the naming of the current component. The established rule set +// ensures that a component.get_full_name() is parsable, unique, printable to order to avoid any ambiguities +// when messages are being emitted. +// +// ruleset a legal name is composed of +// - allowed charset "A-z:_0-9[](){}-: " +// - whitespace-as-is, no-balancing delimiter semantic, no escape sequences +// - path delimiter not allowed anywhere in the name +// +// the check is coded here as a function to complete it in a single function call +// otherwise save/restore issues with the used dpi could occur +//------------------------------------------------------------------------------ + + +class uvm_component_name_check_visitor extends uvm_visitor#(uvm_component); + local uvm_root _root; + + // Function -- NODOCS -- get_name_constraint + // + // This method should return a regex for what is being considered a valid/good component name. + // The visitor will check all component names using this regex and report failing names + + virtual function string get_name_constraint(); + return "/^[][[:alnum:](){}_:-]([][[:alnum:](){} _:-]*[][[:alnum:](){}_:-])?$/"; + endfunction + + virtual function void visit(NODE node); + // dont check the root component + if(_root != node) begin + if ( ! uvm_is_match( get_name_constraint(), node.get_name() ) ) begin + `uvm_warning("UVM/COMP/NAME",$sformatf("the name \"%s\" of the component \"%s\" violates the uvm component name constraints",node.get_name(),node.get_full_name())) + end + end + endfunction + + function new (string name = ""); + super.new(name); + endfunction + + virtual function void begin_v(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + + _root = cs.get_root(); + +`ifdef UVM_NO_DPI + `uvm_info("UVM/COMP/NAMECHECK","This implementation of the component name checks requires DPI to be enabled",UVM_NONE) +`endif + endfunction + +endclass diff --git a/test_regress/t/t_uvm/base/uvm_version.svh b/test_regress/t/t_uvm/base/uvm_version.svh new file mode 100644 index 0000000000..a084d6115b --- /dev/null +++ b/test_regress/t/t_uvm/base/uvm_version.svh @@ -0,0 +1,40 @@ +//---------------------------------------------------------------------- +// Copyright 2012 Paradigm Works +// Copyright 2007-2013 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, Inc. +// Copyright 2011-2012 Cypress Semiconductor Corp. +// 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_VERSION_SVH +`define UVM_VERSION_SVH + +parameter string UVM_VERSION_STRING = "Accellera:1800.2-2017:UVM:1.0"; + +`ifdef UVM_ENABLE_DEPRECATED_API + parameter string uvm_revision = UVM_VERSION_STRING; +`endif // UVM_ENABLE_DEPRECATED_API + +function string uvm_revision_string(); + return UVM_VERSION_STRING; +endfunction + +`endif // UVM_VERSION_SVH diff --git a/test_regress/t/t_uvm/comps/uvm_agent.svh b/test_regress/t/t_uvm/comps/uvm_agent.svh new file mode 100644 index 0000000000..ccf19f1b57 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_agent.svh @@ -0,0 +1,100 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2012 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_agent +// +// The uvm_agent virtual class should be used as the base class for the user- +// defined agents. Deriving from uvm_agent will allow you to distinguish agents +// from other component types also using its inheritance. Such agents will +// automatically inherit features that may be added to uvm_agent in the future. +// +// While an agent's build function, inherited from , can be +// implemented to define any agent topology, an agent typically contains three +// subcomponents: a driver, sequencer, and monitor. If the agent is active, +// subtypes should contain all three subcomponents. If the agent is passive, +// subtypes should contain only the monitor. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.4.1 +virtual class uvm_agent extends uvm_component; + uvm_active_passive_enum is_active = UVM_ACTIVE; + + // TODO: Make ~is_active~ a field via field utils + `uvm_component_abstract_utils(uvm_agent) + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + // + // The int configuration parameter is_active is used to identify whether this + // agent should be acting in active or passive mode. This parameter can + // be set by doing: + // + //| uvm_config_int::set(this, ", "is_active", UVM_ACTIVE); + + // @uvm-ieee 1800.2-2017 auto 13.4.2.1 + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction + + function void build_phase(uvm_phase phase); + int active; + uvm_resource_pool rp; + uvm_resource_types::rsrc_q_t rq; + bit found; + + super.build_phase(phase); + // is_active is treated as if it were declared via `uvm_field_enum, + // which means it matches against uvm_active_passive_enum, int, + // int unsigned, uvm_integral_t, uvm_bitstream_t, and string. + rp = uvm_resource_pool::get(); + rq = rp.lookup_name(get_full_name(), "is_active", null, 0); + uvm_resource_pool::sort_by_precedence(rq); + for (int i = 0; i < rq.size() && !found; i++) begin + uvm_resource_base rsrc = rq.get(i); + `uvm_resource_enum_read(/* SUCCESS */ found, + /* RSRC */ rsrc, + /* TYPE */ uvm_active_passive_enum, + /* VAL */ is_active, + /* OBJ */ this) + end + + endfunction + + // Function -- NODOCS -- get_is_active + // + // Returns UVM_ACTIVE is the agent is acting as an active agent and + // UVM_PASSIVE if it is acting as a passive agent. The default implementation + // is to just return the is_active flag, but the component developer may + // override this behavior if a more complex algorithm is needed to determine + // the active/passive nature of the agent. + + // @uvm-ieee 1800.2-2017 auto 13.4.2.2 + virtual function uvm_active_passive_enum get_is_active(); + return is_active; + endfunction +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_algorithmic_comparator.svh b/test_regress/t/t_uvm/comps/uvm_algorithmic_comparator.svh new file mode 100644 index 0000000000..8ae717e88a --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_algorithmic_comparator.svh @@ -0,0 +1,131 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2014 Semifore +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +// File --NODOCS-- Algorithmic Comparator +// +// A common function of testbenches is to compare streams of transactions for +// equivalence. For example, a testbench may compare a stream of transactions +// from a DUT with expected results. +// +// The UVM library provides a base class called +// and two +// derived classes, which are for comparing +// streams of built-in types and for comparing +// streams of class objects. +// +// The uvm_algorithmic_comparator also compares two streams of transactions; +// however, the transaction streams might be of different type objects. This +// device will use a user-written transformation function to convert one type +// to another before performing a comparison. + + +//------------------------------------------------------------------------------ +// +// CLASS --NODOCS-- uvm_algorithmic_comparator #(BEFORE,AFTER,TRANSFORMER) +// +// Compares two streams of data objects of different types, ~BEFORE~ and ~AFTER~. +// +// The algorithmic comparator is a wrapper around . +// Like the in-order comparator, the algorithmic comparator compares two streams +// of transactions, the ~BEFORE~ stream and the ~AFTER~ stream. It is often the case +// when two streams of transactions need to be compared that the two streams are +// in different forms. That is, the type of the ~BEFORE~ transaction stream is +// different than the type of the ~AFTER~ transaction stream. +// +// The uvm_algorithmic_comparator's ~TRANSFORMER~ type parameter specifies the +// class responsible for converting transactions of type ~BEFORE~ into those of +// type ~AFTER~. This transformer class must provide a transform() method with the +// following prototype: +// +//| function AFTER transform (BEFORE b); +// +// Matches and mismatches are reported in terms of the ~AFTER~ transactions. +// For more information, see the +// class. +// +//------------------------------------------------------------------------------ + + +class uvm_algorithmic_comparator #( type BEFORE=int, + type AFTER=int, + type TRANSFORMER=int) extends uvm_component; + + typedef uvm_algorithmic_comparator #( BEFORE , + AFTER , + TRANSFORMER ) this_type; + + `uvm_component_param_utils(this_type) + `uvm_type_name_decl("uvm_algorithmic_comparator #(BEFORE,AFTER,TRANSFORMER)") + + // Port --NODOCS-- before_export + // + // The export to which a data stream of type BEFORE is sent via a connected + // analysis port. Publishers (monitors) can send in an ordered stream of + // transactions against which the transformed BEFORE transactions will + // (be compared. + + uvm_analysis_imp #(BEFORE, this_type) before_export; + + + // Port --NODOCS-- after_export + // + // The export to which a data stream of type AFTER is sent via a connected + // analysis port. Publishers (monitors) can send in an ordered stream of + // transactions to be transformed and compared to the AFTER transactions. + + uvm_analysis_export #(AFTER) after_export; + + + local uvm_in_order_class_comparator #(AFTER) comp; + local TRANSFORMER m_transformer; + + // Function --NODOCS-- new + // + // Creates an instance of a specialization of this class. + // In addition to the standard uvm_component constructor arguments, ~name~ + // and ~parent~, the constructor takes a handle to a ~transformer~ object, + // which must already be allocated (handles can't be ~null~) and must implement + // the transform() method. + + function new(string name, uvm_component parent=null, TRANSFORMER transformer=null); + + super.new( name , parent ); + + m_transformer = transformer; + comp = new("comp", this ); + + before_export = new("before_analysis_export" , this ); + after_export = new("after_analysis_export" , this ); + endfunction + + virtual function void connect_phase(uvm_phase phase); + after_export.connect( comp.after_export ); + endfunction + + function void write( input BEFORE b ); + comp.before_export.write( m_transformer.transform( b ) ); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_comps.svh b/test_regress/t/t_uvm/comps/uvm_comps.svh new file mode 100644 index 0000000000..131027348a --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_comps.svh @@ -0,0 +1,40 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2017 Cisco Systems, 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. +//------------------------------------------------------------------------------ + + `include "comps/uvm_pair.svh" + `include "comps/uvm_policies.svh" + `include "comps/uvm_in_order_comparator.svh" + `include "comps/uvm_algorithmic_comparator.svh" + `ifdef UVM_ENABLE_DEPRECATED_API + `include "comps/uvm_random_stimulus.svh" + `endif + `include "comps/uvm_subscriber.svh" + + `include "comps/uvm_monitor.svh" + `include "comps/uvm_driver.svh" + `include "comps/uvm_push_driver.svh" + `include "comps/uvm_scoreboard.svh" + `include "comps/uvm_agent.svh" + `include "comps/uvm_env.svh" + `include "comps/uvm_test.svh" diff --git a/test_regress/t/t_uvm/comps/uvm_driver.svh b/test_regress/t/t_uvm/comps/uvm_driver.svh new file mode 100644 index 0000000000..fcab89c9d2 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_driver.svh @@ -0,0 +1,92 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// 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. +//------------------------------------------------------------------------------ + +typedef class uvm_sequence_item; + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_driver #(REQ,RSP) +// +// The base class for drivers that initiate requests for new transactions via +// a uvm_seq_item_pull_port. The ports are typically connected to the exports of +// an appropriate sequencer component. +// +// This driver operates in pull mode. Its ports are typically connected to the +// corresponding exports in a pull sequencer as follows: +// +//| driver.seq_item_port.connect(sequencer.seq_item_export); +//| driver.rsp_port.connect(sequencer.rsp_export); +// +// The ~rsp_port~ needs connecting only if the driver will use it to write +// responses to the analysis export in the sequencer. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.7.1 +class uvm_driver #(type REQ=uvm_sequence_item, + type RSP=REQ) extends uvm_component; + + `uvm_component_param_utils(uvm_driver#(REQ,RSP)) + // TODO: Would it be useful to change this to: + //| `uvm_type_name_decl($sformatf("uvm_driver #(%s,%s)", REQ::type_name(), RSP::type_name())) + `uvm_type_name_decl("uvm_driver #(REQ,RSP)") + + // Port -- NODOCS -- seq_item_port + // + // Derived driver classes should use this port to request items from the + // sequencer. They may also use it to send responses back. + + uvm_seq_item_pull_port #(REQ, RSP) seq_item_port; + + uvm_seq_item_pull_port #(REQ, RSP) seq_item_prod_if; // alias + + // Port -- NODOCS -- rsp_port + // + // This port provides an alternate way of sending responses back to the + // originating sequencer. Which port to use depends on which export the + // sequencer provides for connection. + + uvm_analysis_port #(RSP) rsp_port; + + REQ req; + RSP rsp; + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + function new (string name, uvm_component parent); + super.new(name, parent); + seq_item_port = new("seq_item_port", this); + rsp_port = new("rsp_port", this); + seq_item_prod_if = seq_item_port; + endfunction // new + + virtual function void end_of_elaboration_phase(uvm_phase phase); + if(seq_item_port.size<1) + `uvm_warning("DRVCONNECT","the driver is not connected to a sequencer via the standard mechanisms enabled by connect()") + endfunction +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_env.svh b/test_regress/t/t_uvm/comps/uvm_env.svh new file mode 100644 index 0000000000..9cc9126928 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_env.svh @@ -0,0 +1,49 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_env +// +// The base class for hierarchical containers of other components that +// together comprise a complete environment. The environment may +// initially consist of the entire testbench. Later, it can be reused as +// a sub-environment in even larger system-level environments. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.3.1 +virtual class uvm_env extends uvm_component; + + `uvm_component_abstract_utils(uvm_env) + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + // @uvm-ieee 1800.2-2017 auto 13.3.2 + function new (string name="env", uvm_component parent=null); + super.new(name,parent); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_in_order_comparator.svh b/test_regress/t/t_uvm/comps/uvm_in_order_comparator.svh new file mode 100644 index 0000000000..02491e373a --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_in_order_comparator.svh @@ -0,0 +1,246 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Title --NODOCS-- Comparators +// +// The following classes define comparators for objects and built-in types. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS --NODOCS-- uvm_in_order_comparator #(T,comp_type,convert,pair_type) +// +// Compares two streams of data objects of the type parameter, T. +// These transactions may either be classes or built-in types. To be +// successfully compared, the two streams of data must be in the same order. +// Apart from that, there are no assumptions made about the relative timing of +// the two streams of data. +// +// Type parameters +// +// T - Specifies the type of transactions to be compared. +// +// comp_type - A policy class to compare the two +// transaction streams. It must provide the static method +// "function bit comp(T a, T b)" which returns ~TRUE~ +// if ~a~ and ~b~ are the same. +// +// convert - A policy class to convert the transactions being compared +// to a string. It must provide the static method +// "function string convert2string(T a)". +// +// pair_type - A policy class to allow pairs of transactions to be handled as +// a single type. +// +// Built in types (such as ints, bits, logic, and structs) can be compared using +// the default values for comp_type, convert, and pair_type. For convenience, +// you can use the subtype, +// for built-in types. +// +// When T is a , you can use the convenience subtype +// . +// +// Comparisons are commutative, meaning it does not matter which data stream is +// connected to which export, before_export or after_export. +// +// Comparisons are done in order and as soon as a transaction is received from +// both streams. Internal fifos are used to buffer incoming transactions on one +// stream until a transaction to compare arrives on the other stream. +// +//------------------------------------------------------------------------------ + +class uvm_in_order_comparator + #( type T = int , + type comp_type = uvm_built_in_comp #( T ) , + type convert = uvm_built_in_converter #( T ) , + type pair_type = uvm_built_in_pair #( T ) ) + extends uvm_component; + + typedef uvm_in_order_comparator #(T,comp_type,convert,pair_type) this_type; + `uvm_component_param_utils(this_type) + `uvm_type_name_decl("uvm_in_order_comparator #(T,comp_type,convert,pair_type)") + + // Port --NODOCS-- before_export + // + // The export to which one stream of data is written. The port must be + // connected to an analysis port that will provide such data. + + uvm_analysis_export #(T) before_export; + + + // Port --NODOCS-- after_export + // + // The export to which the other stream of data is written. The port must be + // connected to an analysis port that will provide such data. + + uvm_analysis_export #(T) after_export; + + + // Port --NODOCS-- pair_ap + // + // The comparator sends out pairs of transactions across this analysis port. + // Both matched and unmatched pairs are published via a pair_type objects. + // Any connected analysis export(s) will receive these transaction pairs. + + uvm_analysis_port #(pair_type) pair_ap; + + local uvm_tlm_analysis_fifo #(T) m_before_fifo; + local uvm_tlm_analysis_fifo #(T) m_after_fifo; + + int m_matches, m_mismatches; + + function new(string name, uvm_component parent); + + super.new(name, parent); + + before_export = new("before_export", this); + after_export = new("after_export", this); + pair_ap = new("pair_ap", this); + + m_before_fifo = new("before", this); + m_after_fifo = new("after", this); + m_matches = 0; + m_mismatches = 0; + + endfunction + + virtual function void connect_phase(uvm_phase phase); + before_export.connect(m_before_fifo.analysis_export); + after_export.connect(m_after_fifo.analysis_export); + endfunction + + + // Task- run_phase + // + // Internal method. + // + // Takes pairs of before and after transactions and compares them. + // Status information is updated according to the results of the comparison. + // Each pair is published to the pair_ap analysis port. + + virtual task run_phase(uvm_phase phase); + + pair_type pair; + T b; + T a; + + string s; + super.run_phase(phase); + forever begin + + m_before_fifo.get(b); + m_after_fifo.get(a); + + if(!comp_type::comp(b, a)) begin + + $sformat(s, "%s differs from %s", convert::convert2string(a), + convert::convert2string(b)); + + uvm_report_warning("Comparator Mismatch", s); + + m_mismatches++; + + end + else begin + s = convert::convert2string(b); + uvm_report_info("Comparator Match", s); + m_matches++; + end + + // we make the assumption here that a transaction "sent for + // analysis" is safe from being edited by another process. + // Hence, it is safe not to clone a and b. + + pair = new("after/before"); + pair.first = a; + pair.second = b; + pair_ap.write(pair); + end + + endtask + + + // Function --NODOCS-- flush + // + // This method sets m_matches and m_mismatches back to zero. The + // takes care of flushing the FIFOs. + + virtual function void flush(); + m_matches = 0; + m_mismatches = 0; + endfunction + +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS --NODOCS-- uvm_in_order_built_in_comparator #(T) +// +// This class uses the uvm_built_in_* comparison, converter, and pair classes. +// Use this class for built-in types (int, bit, string, etc.) +// +//------------------------------------------------------------------------------ + +class uvm_in_order_built_in_comparator #(type T=int) + extends uvm_in_order_comparator #(T); + + typedef uvm_in_order_built_in_comparator #(T) this_type; + `uvm_component_param_utils(this_type) + `uvm_type_name_decl("uvm_in_order_built_in_comparator #(T)") + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS --NODOCS-- uvm_in_order_class_comparator #(T) +// +// This class uses the uvm_class_* comparison, converter, and pair classes. +// Use this class for comparing user-defined objects of type T, which must +// provide compare() and convert2string() method. +// +//------------------------------------------------------------------------------ + +class uvm_in_order_class_comparator #( type T = int ) + extends uvm_in_order_comparator #( T , + uvm_class_comp #( T ) , + uvm_class_converter #( T ) , + uvm_class_pair #( T, T ) ); + + typedef uvm_in_order_class_comparator #(T) this_type; + `uvm_component_param_utils(this_type) + `uvm_type_name_decl("uvm_in_order_class_comparator #(T)") + + function new( string name , uvm_component parent); + super.new( name, parent ); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_monitor.svh b/test_regress/t/t_uvm/comps/uvm_monitor.svh new file mode 100644 index 0000000000..d06327f928 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_monitor.svh @@ -0,0 +1,50 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_monitor +// +// This class should be used as the base class for user-defined monitors. +// +// Deriving from uvm_monitor allows you to distinguish monitors from generic +// component types inheriting from uvm_component. Such monitors will +// automatically inherit features that may be added to uvm_monitor in the future. +// +//----------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 13.5.1 +virtual class uvm_monitor extends uvm_component; + + `uvm_component_abstract_utils(uvm_monitor) + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + // @uvm-ieee 1800.2-2017 auto 13.5.2 + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_pair.svh b/test_regress/t/t_uvm/comps/uvm_pair.svh new file mode 100644 index 0000000000..af939304ea --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_pair.svh @@ -0,0 +1,160 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Title -- NODOCS -- uvm_pair classes +//----------------------------------------------------------------------------- +// This section defines container classes for handling value pairs. +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Class -- NODOCS -- uvm_class_pair #(T1,T2) +// +// Container holding handles to two objects whose types are specified by the +// type parameters, T1 and T2. +//----------------------------------------------------------------------------- + +class uvm_class_pair #(type T1=int, T2=T1) extends uvm_object; + + typedef uvm_class_pair #(T1, T2 ) this_type; + + `uvm_object_param_utils(this_type) + `uvm_type_name_decl("uvm_class_pair #(T1,T2)") + +// Variable -- NODOCS -- T1 first +// +// The handle to the first object in the pair + + T1 first; + +// Variable -- NODOCS -- T2 second +// +// The handle to the second object in the pair + + T2 second; + + // Function -- NODOCS -- new + // + // Creates an instance that holds a handle to two objects. + // The optional name argument gives a name to the new pair object. + + function new (string name="", T1 f=null, T2 s=null); + + super.new(name); + + if (f == null) + first = new; + else + first = f; + + if (s == null) + second = new; + else + second = s; + + endfunction + + virtual function string convert2string; + string s; + $sformat(s, "pair : %s, %s", + first.convert2string(), second.convert2string()); + return s; + endfunction + + virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer); + this_type rhs_; + if(!$cast(rhs_,rhs)) begin + `uvm_error("WRONG_TYPE", {"do_compare: rhs argument is not of type '",get_type_name(),"'"}) + return 0; + end + return first.compare(rhs_.first) && second.compare(rhs_.second); + endfunction + + virtual function void do_copy (uvm_object rhs); + this_type rhs_; + if(!$cast(rhs_,rhs)) + `uvm_fatal("WRONG_TYPE", {"do_copy: rhs argument is not of type '",get_type_name(),"'"}) + first.copy(rhs_.first); + second.copy(rhs_.second); + endfunction + +endclass + +//----------------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_built_in_pair #(T1,T2) +// +// Container holding two variables of built-in types (int, string, etc.). The +// types are specified by the type parameters, T1 and T2. +//----------------------------------------------------------------------------- + +class uvm_built_in_pair #(type T1=int, T2=T1) extends uvm_object; + + typedef uvm_built_in_pair #(T1,T2) this_type; + + `uvm_object_param_utils(this_type) + `uvm_type_name_decl("uvm_built_in_pair #(T1,T2)") + +// Variable -- NODOCS -- T1 first +// +// The first value in the pair + + T1 first; + +// Variable -- NODOCS -- T2 second +// +// The second value in the pair + + T2 second; + + // Function -- NODOCS -- new + // + // Creates an instance that holds two built-in type values. + // The optional name argument gives a name to the new pair object. + + function new (string name=""); + super.new(name); + endfunction + + virtual function string convert2string; + return $sformatf("built-in pair : %p, %p", first, second); + endfunction + + virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer); + this_type rhs_; + if(!$cast(rhs_,rhs)) begin + `uvm_error("WRONG_TYPE", {"do_compare: rhs argument is not of type '",get_type_name(),"'"}) + return 0; + end + return first == rhs_.first && second == rhs_.second; + endfunction + + function void do_copy (uvm_object rhs); + this_type rhs_; + if(!$cast(rhs_,rhs)) + `uvm_fatal("WRONG_TYPE", {"do_copy: rhs argument is not of type '",get_type_name(),"'"}) + first = rhs_.first; + second = rhs_.second; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_policies.svh b/test_regress/t/t_uvm/comps/uvm_policies.svh new file mode 100644 index 0000000000..1e851243e3 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_policies.svh @@ -0,0 +1,141 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015 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. +//---------------------------------------------------------------------- + + +// Title -- NODOCS -- Policy Classes +// +// Policy classes are used to implement polymorphic operations that +// differ between built-in types and class-based types. Generic +// components can then be built that work with either classes or +// built-in types, depending on what policy class is used. + + +//---------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_built_in_comp #(T) +// +// This policy class is used to compare built-in types. +// +// Provides a comp method that compares the built-in type, +// T, for which the == operator is defined. +//---------------------------------------------------------------------- + +class uvm_built_in_comp #(type T=int); + + static function bit comp(T a, T b); + return a == b; + endfunction + +endclass + + +//---------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_built_in_converter #(T) +// +// This policy class is used to convert built-in types to strings. +// +// Provides a convert2string method that converts the built-in type, T, +// to a string using the %p format specifier. +//---------------------------------------------------------------------- + +class uvm_built_in_converter #(type T=int); + static function string convert2string(input T t); + return $sformatf("%p" , t ); + endfunction +endclass + + +//---------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_built_in_clone #(T) +// +// This policy class is used to clone built-in types via the = operator. +// +// Provides a clone method that returns a copy of the built-in type, T. +//---------------------------------------------------------------------- + +class uvm_built_in_clone #(type T=int); + + static function T clone(input T from); + return from; + endfunction + +endclass + + +//---------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_class_comp #(T) +// +// This policy class is used to compare two objects of the same type. +// +// Provides a comp method that compares two objects of type T. The +// class T must provide the method "function bit compare(T rhs)", +// similar to the method. +//---------------------------------------------------------------------- + +class uvm_class_comp #(type T=int); + + static function bit comp(input T a, input T b); + return a.compare(b); + endfunction + +endclass + + +//---------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_class_converter #(T) +// +// This policy class is used to convert a class object to a string. +// +// Provides a convert2string method that converts an instance of type T +// to a string. The class T must provide the method +// "function string convert2string()", +// similar to the method. +//---------------------------------------------------------------------- + +class uvm_class_converter #(type T=int); + + static function string convert2string(input T t); + return t.convert2string(); + endfunction + +endclass + + +//---------------------------------------------------------------------- +// CLASS -- NODOCS -- uvm_class_clone #(T) +// +// This policy class is used to clone class objects. +// +// Provides a clone method that returns a copy of the built-in type, T. +// The class T must implement the clone method, to which this class +// delegates the operation. If T is derived from , then +// T must instead implement , either directly or +// indirectly through use of the `uvm_field macros. +//---------------------------------------------------------------------- + +class uvm_class_clone #(type T=int); + + static function uvm_object clone(input T from); + return from.clone(); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_push_driver.svh b/test_regress/t/t_uvm/comps/uvm_push_driver.svh new file mode 100644 index 0000000000..2a4c0176f0 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_push_driver.svh @@ -0,0 +1,93 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_push_driver #(REQ,RSP) +// +// Base class for a driver that passively receives transactions, i.e. does not +// initiate requests transactions. Also known as ~push~ mode. Its ports are +// typically connected to the corresponding ports in a push sequencer as follows: +// +//| push_sequencer.req_port.connect(push_driver.req_export); +//| push_driver.rsp_port.connect(push_sequencer.rsp_export); +// +// The ~rsp_port~ needs connecting only if the driver will use it to write +// responses to the analysis export in the sequencer. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.8.1 +class uvm_push_driver #(type REQ=uvm_sequence_item, + type RSP=REQ) extends uvm_component; + + `uvm_component_param_utils(uvm_push_driver#(REQ,RSP)) + `uvm_type_name_decl("uvm_push_driver #(REQ,RSP)") + + // Port -- NODOCS -- req_export + // + // This export provides the blocking put interface whose default + // implementation produces an error. Derived drivers must override ~put~ + // with an appropriate implementation (and not call super.put). Ports + // connected to this export will supply the driver with transactions. + + uvm_blocking_put_imp #(REQ, uvm_push_driver #(REQ,RSP)) req_export; + + // Port -- NODOCS -- rsp_port + // + // This analysis port is used to send response transactions back to the + // originating sequencer. + + uvm_analysis_port #(RSP) rsp_port; + + REQ req; + RSP rsp; + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + function new (string name, uvm_component parent); + super.new(name, parent); + req_export = new("req_export", this); + rsp_port = new("rsp_port", this); + endfunction + + function void check_port_connections(); + if (req_export.size() != 1) + uvm_report_fatal("Connection Error", + $sformatf("Must connect to seq_item_port(%0d)", + req_export.size()), UVM_NONE); + endfunction + + virtual function void end_of_elaboration_phase(uvm_phase phase); + super.end_of_elaboration_phase(phase); + check_port_connections(); + endfunction + + virtual task put(REQ item); + uvm_report_fatal("UVM_PUSH_DRIVER", "Put task for push driver is not implemented", UVM_NONE); + endtask + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_random_stimulus.svh b/test_regress/t/t_uvm/comps/uvm_random_stimulus.svh new file mode 100644 index 0000000000..8ef08d124d --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_random_stimulus.svh @@ -0,0 +1,132 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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_random_stimulus #(T) +// +// A general purpose unidirectional random stimulus class. +// +// The uvm_random_stimulus class generates streams of T transactions. These streams +// may be generated by the randomize method of T, or the randomize method of +// one of its subclasses. The stream may go indefinitely, until terminated +// by a call to stop_stimulus_generation, or we may specify the maximum number +// of transactions to be generated. +// +// By using inheritance, we can add directed initialization or tidy up after +// random stimulus generation. Simply extend the class and define the run task, +// calling super.run() when you want to begin the random stimulus phase of +// simulation. +// +// While very useful in its own right, this component can also be used as a +// template for defining other stimulus generators, or it can be extended to +// add additional stimulus generation methods and to simplify test writing. +// +//------------------------------------------------------------------------------ + +`ifdef UVM_ENABLE_DEPRECATED_API + +class uvm_random_stimulus #(type T=uvm_transaction) extends uvm_component; + + typedef uvm_random_stimulus #(T) this_type; + `uvm_component_param_utils(this_type) + // TODO: Would this be better as: + //| `uvm_type_name_decl($sformatf("uvm_random_stimulus #(%s)", T::type_name)) + `uvm_type_name_decl("uvm_random_stimulus #(T)") + + // Port -- NODOCS -- blocking_put_port + // + // The blocking_put_port is used to send the generated stimulus to the rest + // of the testbench. + + uvm_blocking_put_port #(T) blocking_put_port; + + + // Function -- NODOCS -- new + // + // Creates a new instance of a specialization of this class. + // Also, displays the random state obtained from a get_randstate call. + // In subsequent simulations, set_randstate can be called with the same + // value to reproduce the same sequence of transactions. + + function new(string name, uvm_component parent); + + super.new(name, parent); + + blocking_put_port=new("blocking_put_port", this); + + uvm_report_info("uvm_stimulus", {"rand state is ", get_randstate()}); + + endfunction + + + local bit m_stop; + + + // Function -- NODOCS -- generate_stimulus + // + // Generate up to max_count transactions of type T. + // If t is not specified, a default instance of T is allocated and used. + // If t is specified, that transaction is used when randomizing. It must + // be a subclass of T. + // + // max_count is the maximum number of transactions to be + // generated. A value of zero indicates no maximum - in + // this case, generate_stimulus will go on indefinitely + // unless stopped by some other process + // + // The transactions are cloned before they are sent out + // over the blocking_put_port + + virtual task generate_stimulus(T t=null, int max_count=0); + + T temp; + + if (t == null) + t = new; + + for (int i=0; (max_count == 0 || i < max_count) && !m_stop; i++) begin + + if (! t.randomize() ) + uvm_report_warning ("RANDFL", "Randomization failed in generate_stimulus"); + + $cast(temp, t.clone()); + uvm_report_info("stimulus generation", temp.convert2string()); + blocking_put_port.put(temp); + end + endtask + + + // Function -- NODOCS -- stop_stimulus_generation + // + // Stops the generation of stimulus. + // If a subclass of this method has forked additional + // processes, those processes will also need to be + // stopped in an overridden version of this method + + virtual function void stop_stimulus_generation; + m_stop = 1; + endfunction + + +endclass : uvm_random_stimulus +`endif //UVM_ENABLE_DEPRECATED_API diff --git a/test_regress/t/t_uvm/comps/uvm_scoreboard.svh b/test_regress/t/t_uvm/comps/uvm_scoreboard.svh new file mode 100644 index 0000000000..1a783a028a --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_scoreboard.svh @@ -0,0 +1,51 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_scoreboard +// +// The uvm_scoreboard virtual class should be used as the base class for +// user-defined scoreboards. +// +// Deriving from uvm_scoreboard will allow you to distinguish scoreboards from +// other component types inheriting directly from uvm_component. Such +// scoreboards will automatically inherit and benefit from features that may be +// added to uvm_scoreboard in the future. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.6.1 +virtual class uvm_scoreboard extends uvm_component; + + `uvm_component_abstract_utils(uvm_scoreboard) + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_subscriber.svh b/test_regress/t/t_uvm/comps/uvm_subscriber.svh new file mode 100644 index 0000000000..1376bf30ec --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_subscriber.svh @@ -0,0 +1,68 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_subscriber +// +// This class provides an analysis export for receiving transactions from a +// connected analysis export. Making such a connection "subscribes" this +// component to any transactions emitted by the connected analysis port. +// +// Subtypes of this class must define the write method to process the incoming +// transactions. This class is particularly useful when designing a coverage +// collector that attaches to a monitor. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.9.1 +virtual class uvm_subscriber #(type T=int) extends uvm_component; + + typedef uvm_subscriber #(T) this_type; + + // Port -- NODOCS -- analysis_export + // + // This export provides access to the write method, which derived subscribers + // must implement. + + uvm_analysis_imp #(T, this_type) analysis_export; + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + function new (string name, uvm_component parent); + super.new(name, parent); + analysis_export = new("analysis_imp", this); + endfunction + + // Function -- NODOCS -- write + // + // A pure virtual method that must be defined in each subclass. Access + // to this method by outside components should be done via the + // analysis_export. + + // @uvm-ieee 1800.2-2017 auto 13.9.3.2 + pure virtual function void write(T t); + +endclass diff --git a/test_regress/t/t_uvm/comps/uvm_test.svh b/test_regress/t/t_uvm/comps/uvm_test.svh new file mode 100644 index 0000000000..c93ce51626 --- /dev/null +++ b/test_regress/t/t_uvm/comps/uvm_test.svh @@ -0,0 +1,78 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_test +// +// This class is the virtual base class for the user-defined tests. +// +// The uvm_test virtual class should be used as the base class for user-defined +// tests. Doing so provides the ability to select which test to execute using +// the UVM_TESTNAME command line or argument to the task. +// +// For example +// +//| prompt> SIM_COMMAND +UVM_TESTNAME=test_bus_retry +// +// The global run_test() task should be specified inside an initial block +// such as +// +//| initial run_test(); +// +// Multiple tests, identified by their type name, are compiled in and then +// selected for execution from the command line without need for recompilation. +// Random seed selection is also available on the command line. +// +// If +UVM_TESTNAME=test_name is specified, then an object of type 'test_name' +// is created by factory and phasing begins. Here, it is presumed that the +// test will instantiate the test environment, or the test environment will +// have already been instantiated before the call to run_test(). +// +// If the specified test_name cannot be created by the , then a +// fatal error occurs. If run_test() is called without UVM_TESTNAME being +// specified, then all components constructed before the call to run_test will +// be cycled through their simulation phases. +// +// Deriving from uvm_test will allow you to distinguish tests from other +// component types that inherit from uvm_component directly. Such tests will +// automatically inherit features that may be added to uvm_test in the future. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 13.2.1 +virtual class uvm_test extends uvm_component; + + `uvm_component_abstract_utils(uvm_test) + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for : ~name~ is the name of the + // instance, and ~parent~ is the handle to the hierarchical parent, if any. + + // @uvm-ieee 1800.2-2017 auto 13.2.2 + function new (string name, uvm_component parent); + super.new(name,parent); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/dap/uvm_dap.svh b/test_regress/t/t_uvm/dap/uvm_dap.svh new file mode 100644 index 0000000000..4bbbefd230 --- /dev/null +++ b/test_regress/t/t_uvm/dap/uvm_dap.svh @@ -0,0 +1,34 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// 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_DAP_SVH + `define UVM_DAP_SVH + +// Set/Get DAPS + `include "dap/uvm_set_get_dap_base.svh" + `include "dap/uvm_simple_lock_dap.svh" + `include "dap/uvm_get_to_lock_dap.svh" + `include "dap/uvm_set_before_get_dap.svh" + +`endif // UVM_DAP_SVH diff --git a/test_regress/t/t_uvm/dap/uvm_get_to_lock_dap.svh b/test_regress/t/t_uvm/dap/uvm_get_to_lock_dap.svh new file mode 100644 index 0000000000..30a3c8041e --- /dev/null +++ b/test_regress/t/t_uvm/dap/uvm_get_to_lock_dap.svh @@ -0,0 +1,153 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 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. +//------------------------------------------------------------------------------ + +// Class -- NODOCS -- uvm_get_to_lock_dap +// Provides a 'Get-To-Lock' Data Access Policy. +// +// The 'Get-To-Lock' Data Access Policy allows for any number of 'sets', +// until the value is retrieved via a 'get'. Once 'get' has been called, +// it is illegal to 'set' a new value. +// +// The UVM uses this policy to protect the ~starting phase~ and ~automatic objection~ +// values in . +// + +class uvm_get_to_lock_dap#(type T=int) extends uvm_set_get_dap_base#(T); + + // Used for self-references + typedef uvm_get_to_lock_dap#(T) this_type; + + // Parameterized Utils + `uvm_object_param_utils(uvm_get_to_lock_dap#(T)) + + // Stored data + local T m_value; + + // Lock state + local bit m_locked; + + // Function -- NODOCS -- new + // Constructor + function new(string name="unnamed-uvm_get_to_lock_dap#(T)"); + super.new(name); + m_locked = 0; + endfunction : new + + // Group -- NODOCS -- Set/Get Interface + + // Function -- NODOCS -- set + // Updates the value stored within the DAP. + // + // ~set~ will result in an error if the value has + // already been retrieved via a call to ~get~. + virtual function void set(T value); + if (m_locked) + `uvm_error("UVM/GET_TO_LOCK_DAP/SAG", + $sformatf("Attempt to set new value on '%s', but the data access policy forbids setting after a get!", + get_full_name())) + else begin + m_value = value; + end + endfunction : set + + // Function -- NODOCS -- try_set + // Attempts to update the value stored within the DAP. + // + // ~try_set~ will return a 1 if the value was successfully + // updated, or a '0' if the value cannot be updated due + // to ~get~ having been called. No errors will be reported + // if ~try_set~ fails. + virtual function bit try_set(T value); + if (m_locked) + return 0; + else begin + m_value = value; + return 1; + end + endfunction : try_set + + // Function -- NODOCS -- get + // Returns the current value stored within the DAP, and 'locks' the DAP. + // + // After a 'get', the value contained within the DAP cannot + // be changed. + virtual function T get(); + m_locked = 1; + return m_value; + endfunction : get + + // Function -- NODOCS -- try_get + // Retrieves the current value stored within the DAP, and 'locks' the DAP. + // + // ~try_get~ will always return 1. + virtual function bit try_get(output T value); + value = get(); + return 1; + endfunction : try_get + + // Group -- NODOCS -- Introspection + // + // The ~uvm_get_to_lock_dap~ cannot support the standard UVM + // instrumentation methods (~copy~, ~clone~, ~pack~ and + // ~unpack~), due to the fact that they would potentially + // violate the access policy. + // + // A call to any of these methods will result in an error. + + virtual function void do_copy(uvm_object rhs); + `uvm_error("UVM/GET_TO_LOCK_DAP/CPY", + "'copy()' is not supported for 'uvm_get_to_lock_dap#(T)'") + endfunction : do_copy + + virtual function void do_pack(uvm_packer packer); + `uvm_error("UVM/GET_TO_LOCK_DAP/PCK", + "'pack()' is not supported for 'uvm_get_to_lock_dap#(T)'") + endfunction : do_pack + + virtual function void do_unpack(uvm_packer packer); + `uvm_error("UVM/GET_TO_LOCK_DAP/UPK", + "'unpack()' is not supported for 'uvm_get_to_lock_dap#(T)'") + endfunction : do_unpack + + // Group- Reporting + + // Function- convert2string + virtual function string convert2string(); + if (m_locked) + return $sformatf("(%s) %0p [LOCKED]", `uvm_typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNLOCKED]", `uvm_typename(m_value), m_value); + endfunction : convert2string + + // Function- do_print + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field_int("lock_state", m_locked, $bits(m_locked)); + printer.print_generic("value", + `uvm_typename(m_value), + 0, + $sformatf("%0p", m_value)); + + endfunction : do_print + +endclass // uvm_get_to_lock_dap diff --git a/test_regress/t/t_uvm/dap/uvm_set_before_get_dap.svh b/test_regress/t/t_uvm/dap/uvm_set_before_get_dap.svh new file mode 100644 index 0000000000..8c379d3260 --- /dev/null +++ b/test_regress/t/t_uvm/dap/uvm_set_before_get_dap.svh @@ -0,0 +1,183 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 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. +//------------------------------------------------------------------------------ + +// Class -- NODOCS -- uvm_set_before_get_dap +// Provides a 'Set Before Get' Data Access Policy. +// +// The 'Set Before Get' Data Access Policy enforces that the value must +// be written at ~least~ once before it is read. This DAP can be used to +// pass shared information to multiple components during standard configuration, +// even if that information hasn't yet been determined. +// +// Such DAP objects can be useful for passing a 'placeholder' reference, before +// the information is actually available. A good example of this would be +// the virtual sequencer: +// +//| typedef uvm_set_before_get_dap#(uvm_sequencer_base) seqr_dap_t; +//| virtual_seqeuncer_type virtual_sequencer; +//| agent_type my_agent; +//| seqr_dap_t seqr_dap; +//| +//| function void my_env::build_phase(uvm_phase phase); +//| seqr_dap = seqr_dap_t::type_id::create("seqr_dap"); +//| // Pass the DAP, because we don't have a reference to the +//| // real sequencer yet... +//| uvm_config_db#(seqr_dap_t)::set(this, "virtual_sequencer", "seqr_dap", seqr_dap); +//| +//| // Create the virtual sequencer +//| virtual_sequencer = virtual_sequencer_type::type_id::create("virtual_sequencer", this); +//| +//| // Create the agent +//| agent = agent_type::type_id::create("agent", this); +//| endfunction +//| +//| function void my_env::connect_phase(uvm_phase phase); +//| // Now that we know the value is good, we can set it +//| seqr_dap.set(agent.sequencer); +//| endfunction +// +// In the example above, the environment didn't have a reference to the +// agent's sequencer yet, because the agent hadn't executed its ~build_phase~. +// The environment needed to give the virtual sequencer a "Set before get" DAP +// so that the virtual sequencer (and any sequences one it), could ~eventually~ +// see the agent's sequencer, when the reference was finally available. If +// the virtual sequencer (or any sequences on it) attempted to 'get' the +// reference to the agent's sequencer ~prior~ to the environment assigning it, +// an error would have been reported. + +class uvm_set_before_get_dap#(type T=int) extends uvm_set_get_dap_base#(T); + + // Used for self-references + typedef uvm_set_before_get_dap#(T) this_type; + + // Parameterized Utils + `uvm_object_param_utils(uvm_set_before_get_dap#(T)) + + // Stored data + local T m_value; + + // Set state + local bit m_set; + + // Function -- NODOCS -- new + // Constructor + function new(string name="unnamed-uvm_set_before_get_dap#(T)"); + super.new(name); + m_set = 0; + endfunction : new + + // Group -- NODOCS -- Set/Get Interface + + // Function -- NODOCS -- set + // Updates the value stored within the DAP. + // + virtual function void set(T value); + m_set = 1; + m_value = value; + endfunction : set + + // Function -- NODOCS -- try_set + // Attempts to update the value stored within the DAP. + // + // ~try_set~ will always return a 1. + virtual function bit try_set(T value); + set(value); + return 1; + endfunction : try_set + + // Function -- NODOCS -- get + // Returns the current value stored within the DAP. + // + // If 'get' is called before a call to or , then + // an error will be reported. + virtual function T get(); + if (!m_set) begin + `uvm_error("UVM/SET_BEFORE_GET_DAP/NO_SET", + $sformatf("Attempt to get value on '%s', but the data access policy forbits calling 'get' prior to calling 'set' or 'try_set'!", + get_full_name())) + end + return m_value; + endfunction : get + + // Function -- NODOCS -- try_get + // Attempts to retrieve the current value stored within the DAP + // + // If the value has not been 'set', then try_get will return a 0, + // otherwise it will return a 1, and set ~value~ to the current + // value stored within the DAP. + virtual function bit try_get(output T value); + if (!m_set) begin + return 0; + end + else begin + value = m_value; + return 1; + end + endfunction : try_get + + // Group -- NODOCS -- Introspection + // + // The ~uvm_set_before_get_dap~ cannot support the standard UVM + // instrumentation methods (~copy~, ~clone~, ~pack~ and + // ~unpack~), due to the fact that they would potentially + // violate the access policy. + // + // A call to any of these methods will result in an error. + + virtual function void do_copy(uvm_object rhs); + `uvm_error("UVM/SET_BEFORE_GET_DAP/CPY", + "'copy()' is not supported for 'uvm_set_before_get_dap#(T)'") + endfunction : do_copy + + virtual function void do_pack(uvm_packer packer); + `uvm_error("UVM/SET_BEFORE_GET_DAP/PCK", + "'pack()' is not supported for 'uvm_set_before_get_dap#(T)'") + endfunction : do_pack + + virtual function void do_unpack(uvm_packer packer); + `uvm_error("UVM/SET_BEFORE_GET_DAP/UPK", + "'unpack()' is not supported for 'uvm_set_before_get_dap#(T)'") + endfunction : do_unpack + + // Group- Reporting + + // Function- convert2string + virtual function string convert2string(); + if (m_set) + return $sformatf("(%s) %0p [SET]", `uvm_typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNSET]", `uvm_typename(m_value), m_value); + endfunction : convert2string + + // Function- do_print + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field_int("set_state", m_set, $bits(m_set)); + printer.print_generic("value", + `uvm_typename(m_value), + 0, + $sformatf("%0p", m_value)); + + endfunction : do_print + +endclass // uvm_set_before_get_dap diff --git a/test_regress/t/t_uvm/dap/uvm_set_get_dap_base.svh b/test_regress/t/t_uvm/dap/uvm_set_get_dap_base.svh new file mode 100644 index 0000000000..2c89ddfd0a --- /dev/null +++ b/test_regress/t/t_uvm/dap/uvm_set_get_dap_base.svh @@ -0,0 +1,81 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 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. +//------------------------------------------------------------------------------ + +// Class -- NODOCS -- uvm_set_get_dap_base +// Provides the 'set' and 'get' interface for Data Access Policies (DAPs) +// +// The 'Set/Get' base class simply provides a common interface for +// the various DAPs to implement. This provides a mechanism for +// consistent implementations of similar DAPs. +// + +virtual class uvm_set_get_dap_base#(type T=int) extends uvm_object; + + // Used for self references + typedef uvm_set_get_dap_base#(T) this_type; + + // Function -- NODOCS -- new + // Constructor + function new(string name="unnamed-uvm_set_get_dap_base#(T)"); + super.new(name); + endfunction : new + + // Group -- NODOCS -- Set/Get Interface + // + // All implementations of the ~uvm_set_get_dap_base~ class must + // provide an implementation of the four basic "Set and Get" + // accessors. + // + + // Function -- NODOCS -- set + // Sets the value contained within the resource. + // + // Depending on the DAP policies, an error may be reported if + // it is illegal to 'set' the value at this time. + pure virtual function void set(T value); + + // Function -- NODOCS -- try_set + // Attempts to set the value contained within the resource. + // + // If the DAP policies forbid setting at this time, then + // the method will return 0, however no errors will be + // reported. Otherwise, the method will return 1, and + // will be treated like a standard call. + pure virtual function bit try_set(T value); + + // Function -- NODOCS -- get + // Retrieves the value contained within the resource. + // + // Depending on the DAP policies, an error may be reported + // if it is illegal to 'get' the value at this time. + pure virtual function T get(); + + // Function -- NODOCS -- try_get + // Attempts to retrieve the value contained within the resource. + // + // If the DAP policies forbid retrieving at this time, then + // the method will return 0, however no errors will be + // reported. Otherwise, the method will return 1, and will + // be treated like a standard call. + pure virtual function bit try_get(output T value); + +endclass : uvm_set_get_dap_base diff --git a/test_regress/t/t_uvm/dap/uvm_simple_lock_dap.svh b/test_regress/t/t_uvm/dap/uvm_simple_lock_dap.svh new file mode 100644 index 0000000000..a292ffeaa3 --- /dev/null +++ b/test_regress/t/t_uvm/dap/uvm_simple_lock_dap.svh @@ -0,0 +1,178 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2015 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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_simple_lock_dap +// Provides a 'Simple Lock' Data Access Policy. +// +// The 'Simple Lock' Data Access Policy allows for any number of 'sets', +// so long as the value is not 'locked'. The value can be retrieved using +// 'get' at any time. +// +// The UVM uses this policy to protect the ~file name~ value in the +// . +// + +class uvm_simple_lock_dap#(type T=int) extends uvm_set_get_dap_base#(T); + + // Used for self-references + typedef uvm_simple_lock_dap#(T) this_type; + + // Parameterized Utils + `uvm_object_param_utils(uvm_simple_lock_dap#(T)) + + // Stored data + local T m_value; + + // Lock state + local bit m_locked; + + // Function -- NODOCS -- new + // Constructor + function new(string name="unnamed-uvm_simple_lock_dap#(T)"); + super.new(name); + m_locked = 0; + endfunction : new + + // Group -- NODOCS -- Set/Get Interface + + // Function -- NODOCS -- set + // Updates the value stored within the DAP. + // + // ~set~ will result in an error if the DAP has + // been locked. + virtual function void set(T value); + if (m_locked) + `uvm_error("UVM/SIMPLE_LOCK_DAP/SAG", + $sformatf("Attempt to set new value on '%s', but the data access policy forbids setting while locked!", + get_full_name())) + else begin + m_value = value; + end + endfunction : set + + // Function -- NODOCS -- try_set + // Attempts to update the value stored within the DAP. + // + // ~try_set~ will return a 1 if the value was successfully + // updated, or a 0 if the value can not be updated due + // to the DAP being locked. No errors will be reported + // if ~try_set~ fails. + virtual function bit try_set(T value); + if (m_locked) + return 0; + else begin + m_value = value; + return 1; + end + endfunction : try_set + + // Function -- NODOCS -- get + // Returns the current value stored within the DAP + // + virtual function T get(); + return m_value; + endfunction : get + + // Function -- NODOCS -- try_get + // Retrieves the current value stored within the DAP + // + // ~try_get~ will always return 1. + virtual function bit try_get(output T value); + value = get(); + return 1; + endfunction : try_get + + // Group -- NODOCS -- Locking + + // Function -- NODOCS -- lock + // Locks the data value + // + // The data value cannot be updated via or while locked. + function void lock(); + m_locked = 1; + endfunction : lock + + // Function -- NODOCS -- unlock + // Unlocks the data value + // + function void unlock(); + m_locked = 0; + endfunction : unlock + + // Function -- NODOCS -- is_locked + // Returns the state of the lock. + // + // Returns: + // 1 - The value is locked + // 0 - The value is unlocked + function bit is_locked(); + return m_locked; + endfunction : is_locked + + // Group -- NODOCS -- Introspection + // + // The ~uvm_simple_lock_dap~ cannot support the standard UVM + // instrumentation methods (~copy~, ~clone~, ~pack~ and + // ~unpack~), due to the fact that they would potentially + // violate the access policy. + // + // A call to any of these methods will result in an error. + + virtual function void do_copy(uvm_object rhs); + `uvm_error("UVM/SIMPLE_LOCK_DAP/CPY", + "'copy()' is not supported for 'uvm_simple_lock_dap#(T)'") + endfunction : do_copy + + virtual function void do_pack(uvm_packer packer); + `uvm_error("UVM/SIMPLE_LOCK_DAP/PCK", + "'pack()' is not supported for 'uvm_simple_lock_dap#(T)'") + endfunction : do_pack + + virtual function void do_unpack(uvm_packer packer); + `uvm_error("UVM/SIMPLE_LOCK_DAP/UPK", + "'unpack()' is not supported for 'uvm_simple_lock_dap#(T)'") + endfunction : do_unpack + + // Group- Reporting + + // Function- convert2string + virtual function string convert2string(); + if (m_locked) + return $sformatf("(%s) %0p [LOCKED]", `uvm_typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNLOCKED]", `uvm_typename(m_value), m_value); + endfunction : convert2string + + // Function- do_print + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field("lock_state", m_locked, $bits(m_locked)); + printer.print_generic("value", + `uvm_typename(m_value), + 0, + $sformatf("%0p", m_value)); + + endfunction : do_print + +endclass // uvm_simple_lock_dap diff --git a/test_regress/t/t_uvm/deprecated/macros/uvm_object_defines.svh b/test_regress/t/t_uvm/deprecated/macros/uvm_object_defines.svh new file mode 100644 index 0000000000..8a996efbf3 --- /dev/null +++ b/test_regress/t/t_uvm/deprecated/macros/uvm_object_defines.svh @@ -0,0 +1,2516 @@ +//------------------------------------------------------------------------------ +// Copyright 2012 Aldec +// Copyright 2007-2012 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2012 AMD +// Copyright 2012-2018 NVIDIA Corporation +// Copyright 2012-2018 Cisco Systems, Inc. +// Copyright 2012 Accellera Systems Initiative +// 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. +//------------------------------------------------------------------------------ + + +// This file is the DEPRECATED version of uvm_object_defines.svh +// it contains versions of the macros that support functionality which was +// deprecated between UVM 1.2 and 1800.2-2017. + + + +`ifndef UVM_OBJECT_DEFINES_SVH +`define UVM_OBJECT_DEFINES_SVH + +`ifdef UVM_EMPTY_MACROS + +`define uvm_field_utils_begin(T) +`define uvm_field_utils_end +`define uvm_object_utils(T) +`define uvm_object_param_utils(T) +`define uvm_object_utils_begin(T) +`define uvm_object_param_utils_begin(T) +`define uvm_object_abstract_utils(T) +`define uvm_object_abstract_param_utils(T) +`define uvm_object_abstract_utils_begin(T) +`define uvm_object_abstract_param_utils_begin(T) +`define uvm_object_abstract_utils_end +`define uvm_component_utils(T) +`define uvm_component_param_utils(T) +`define uvm_component_utils_begin(T) +`define uvm_component_param_utils_begin(T) +`define uvm_component_abstract_utils(T) +`define uvm_component_abstract_param_utils(T) +`define uvm_component_abstract_utils_begin(T) +`define uvm_component_abstract_param_utils_begin(T) +`define uvm_component_utils_end +`define uvm_field_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_real(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_enum(T,ARG,FLAG=UVM_DEFAULT) +`define uvm_field_object(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_event(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_array_enum(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_array_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_sarray_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_sarray_enum(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_array_object(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_sarray_object(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_array_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_sarray_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_queue_enum(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_queue_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_queue_object(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_queue_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_string_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_object_string(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_int_unsigned(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_integer(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_integer_unsigned(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_byte(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_byte_unsigned(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_shortint(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_shortint_unsigned(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_longint(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_longint_unsigned(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_int_key(KEY, ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_string_int(ARG,FLAG=UVM_DEFAULT) +`define uvm_field_aa_object_int(ARG,FLAG=UVM_DEFAULT) + +`else + +//------------------------------------------------------------------------------ +// +// Title -- NODOCS -- Utility and Field Macros for Components and Objects +// +// Group -- NODOCS -- Utility Macros +// +// The ~utils~ macros define the infrastructure needed to enable the +// object/component for correct factory operation. See <`uvm_object_utils> and +// <`uvm_component_utils> for details. +// +// A ~utils~ macro should be used inside ~every~ user-defined class that extends +// directly or indirectly, including and +// . +// +// Below is an example usage of the ~utils~ macro for a user-defined object. +// +//| class mydata extends uvm_object; +//| +//| `uvm_object_utils(mydata) +//| +//| // declare data properties +//| +//| function new(string name="mydata_inst"); +//| super.new(name); +//| endfunction +//| +//| endclass +// +// Below is an example usage of a ~utils~ macro for a user-defined component. +// +//| class my_comp extends uvm_component; +//| +//| `uvm_component_utils(my_comp) +//| +//| // declare data properties +//| +//| function new(string name, uvm_component parent=null); +//| super.new(name,parent); +//| endfunction +//| +//| endclass +// +//------------------------------------------------------------------------------ + + +// Define - UVM_FIELD_FLAG_SIZE +// +// The macro defines the number of bits in uvm_field_flag_t. It may be defined by the user but it +// must be at least as large as parameter UVM_FIELD_FLAG_RESERVED_BITS. +// +`ifndef UVM_FIELD_FLAG_SIZE + `define UVM_FIELD_FLAG_SIZE UVM_FIELD_FLAG_RESERVED_BITS +`endif + + +// Definitions for the user to use inside their derived data class declarations. + +// MACRO -- NODOCS -- `uvm_field_utils_begin + +// MACRO -- NODOCS -- `uvm_field_utils_end +// +// These macros form a block in which `uvm_field_* macros can be placed. +// Used as +// +//| `uvm_field_utils_begin(TYPE) +//| `uvm_field_* macros here +//| `uvm_field_utils_end +// +// +// These macros do ~not~ perform factory registration nor implement the +// ~get_type_name~ and ~create~ methods. Use this form when you need custom +// implementations of these two methods, or when you are setting up field macros +// for an abstract class (i.e. virtual class). + +// Implementation Note: The `uvm_field_utils_begin macro creates a new local +// function "__m_uvm_execute_field_op", which has a similar signature to +// , but the arguments are named differently so as to prevent +// potential collisions with field names. For example, if the user had a +// field named "op", then that could collide with the "op" argument of the +// method. + +`define uvm_field_utils_begin(T) \ +function void do_execute_op( uvm_field_op op ); \ + super.do_execute_op(op); \ + __m_uvm_execute_field_op(op); \ +endfunction : do_execute_op \ +function void __m_uvm_execute_field_op( uvm_field_op __local_op__ ); \ + uvm_field_flag_t local_op_type__; /* Used to avoid re-querying */ \ + T local_rhs__; /* Used for $casting copy and compare */ \ + uvm_resource_base local_rsrc__; /* Used for UVM_SET ops */ \ + string local_rsrc_name__; \ + uvm_object local_obj__; /* Used when trying to read uvm_object resources */ \ + bit local_success__; /* Used when trying to read resources */ \ + typedef T __local_type__; /* Used for referring to type T in field macros */ \ + int local_size__; /* Used when unpacking size values */ \ + /* All possible policy classes */ \ + /* Using the same name as the do_* methods, allows macro reuse */ \ + uvm_printer __local_printer__; \ + uvm_comparer __local_comparer__; \ + uvm_recorder __local_recorder__; \ + uvm_packer __local_packer__; \ + uvm_copier __local_copier__; \ + void'($cast(local_rhs__, __local_op__.get_rhs())); \ + if (($cast(local_rsrc__, __local_op__.get_rhs())) && \ + (local_rsrc__ != null)) \ + local_rsrc_name__ = local_rsrc__.get_name(); \ + local_op_type__ = __local_op__.get_op_type(); \ + case (local_op_type__) \ + UVM_PRINT: begin \ + $cast(__local_printer__, __local_op__.get_policy()); \ + end \ + UVM_COMPARE: begin \ + if (local_rhs__ == null) return; \ + $cast(__local_comparer__, __local_op__.get_policy()); \ + end \ + UVM_RECORD: begin \ + $cast(__local_recorder__, __local_op__.get_policy()); \ + end \ + UVM_PACK, UVM_UNPACK: begin \ + $cast(__local_packer__, __local_op__.get_policy()); \ + end \ + UVM_COPY: begin \ + if (local_rhs__ == null) return; \ + $cast(__local_copier__, __local_op__.get_policy()); \ + end \ + UVM_SET: begin \ + if (local_rsrc__ == null) return; \ + end \ + default: \ + return; /* unknown op, just return */ \ + endcase \ + +`define uvm_field_utils_end \ +endfunction : __m_uvm_execute_field_op + + +// MACRO -- NODOCS -- `uvm_object_utils + +// MACRO -- NODOCS -- `uvm_object_param_utils + +// MACRO -- NODOCS -- `uvm_object_utils_begin + +// MACRO -- NODOCS -- `uvm_object_param_utils_begin + +// MACRO -- NODOCS -- `uvm_object_utils_end +// +// -based class declarations may contain one of the above forms of +// utility macros. +// +// For simple objects with no field macros, use +// +//| `uvm_object_utils(TYPE) +// +// For simple objects with field macros, use +// +//| `uvm_object_utils_begin(TYPE) +//| `uvm_field_* macro invocations here +//| `uvm_object_utils_end +// +// For parameterized objects with no field macros, use +// +//| `uvm_object_param_utils(TYPE) +// +// For parameterized objects, with field macros, use +// +//| `uvm_object_param_utils_begin(TYPE) +//| `uvm_field_* macro invocations here +//| `uvm_object_utils_end +// +// Simple (non-parameterized) objects use the uvm_object_utils* versions, which +// do the following: +// +// o Implements get_type_name, which returns TYPE as a string +// +// o Implements create, which allocates an object of type TYPE by calling its +// constructor with no arguments. TYPE's constructor, if defined, must have +// default values on all it arguments. +// +// o Registers the TYPE with the factory, using the string TYPE as the factory +// lookup string for the type. +// +// o Implements the static get_type() method which returns a factory +// proxy object for the type. +// +// o Implements the virtual get_object_type() method which works just like the +// static get_type() method, but operates on an already allocated object. +// +// Parameterized classes must use the uvm_object_param_utils* versions. They +// differ from <`uvm_object_utils> only in that they do not supply a type name +// when registering the object with the factory. As such, name-based lookup with +// the factory for parameterized classes is not possible. +// +// The macros with _begin suffixes are the same as the non-suffixed versions +// except that they also start a block in which `uvm_field_* macros can be +// placed. The block must be terminated by `uvm_object_utils_end. +// + +`define uvm_object_utils(T) \ + `m_uvm_object_registry_internal(T,T) \ + `m_uvm_object_create_func(T) \ + `uvm_type_name_decl(`"T`") + +`define uvm_object_param_utils(T) \ + `m_uvm_object_registry_param(T) \ + `m_uvm_object_create_func(T) + +`define uvm_object_utils_begin(T) \ + `uvm_object_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_object_param_utils_begin(T) \ + `uvm_object_param_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_object_abstract_utils(T) \ + `m_uvm_object_abstract_registry_internal(T,T) \ + `uvm_type_name_decl(`"T`") + +`define uvm_object_abstract_param_utils(T) \ + `m_uvm_object_abstract_registry_param(T) + +`define uvm_object_abstract_utils_begin(T) \ + `uvm_object_abstract_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_object_abstract_param_utils_begin(T) \ + `uvm_object_abstract_param_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_object_utils_end \ + `uvm_field_utils_end + +// MACRO -- NODOCS -- `uvm_component_utils + +// MACRO -- NODOCS -- `uvm_component_param_utils + +// MACRO -- NODOCS -- `uvm_component_utils_begin + +// MACRO -- NODOCS -- `uvm_component_param_utils_begin + +// MACRO -- NODOCS -- `uvm_component_end +// +// uvm_component-based class declarations may contain one of the above forms of +// utility macros. +// +// For simple components with no field macros, use +// +//| `uvm_component_utils(TYPE) +// +// For simple components with field macros, use +// +//| `uvm_component_utils_begin(TYPE) +//| `uvm_field_* macro invocations here +//| `uvm_component_utils_end +// +// For parameterized components with no field macros, use +// +//| `uvm_component_param_utils(TYPE) +// +// For parameterized components with field macros, use +// +//| `uvm_component_param_utils_begin(TYPE) +//| `uvm_field_* macro invocations here +//| `uvm_component_utils_end +// +// Simple (non-parameterized) components must use the uvm_components_utils* +// versions, which do the following: +// +// o Implements get_type_name, which returns TYPE as a string. +// +// o Implements create, which allocates a component of type TYPE using a two +// argument constructor. TYPE's constructor must have a name and a parent +// argument. +// +// o Registers the TYPE with the factory, using the string TYPE as the factory +// lookup string for the type. +// +// o Implements the static get_type() method which returns a factory +// proxy object for the type. +// +// o Implements the virtual get_object_type() method which works just like the +// static get_type() method, but operates on an already allocated object. +// +// Parameterized classes must use the uvm_object_param_utils* versions. They +// differ from `uvm_object_utils only in that they do not supply a type name +// when registering the object with the factory. As such, name-based lookup with +// the factory for parameterized classes is not possible. +// +// The macros with _begin suffixes are the same as the non-suffixed versions +// except that they also start a block in which `uvm_field_* macros can be +// placed. The block must be terminated by `uvm_component_utils_end. +// + +`define uvm_component_utils(T) \ + `m_uvm_component_registry_internal(T,T) \ + `uvm_type_name_decl(`"T`") \ + +`define uvm_component_param_utils(T) \ + `m_uvm_component_registry_param(T) \ + + +`define uvm_component_utils_begin(T) \ + `uvm_component_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_component_param_utils_begin(T) \ + `uvm_component_param_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_component_abstract_utils(T) \ + `m_uvm_component_abstract_registry_internal(T,T) \ + `uvm_type_name_decl(`"T`") \ + +`define uvm_component_abstract_param_utils(T) \ + `m_uvm_component_abstract_registry_param(T) \ + + +`define uvm_component_abstract_utils_begin(T) \ + `uvm_component_abstract_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_component_abstract_param_utils_begin(T) \ + `uvm_component_abstract_param_utils(T) \ + `uvm_field_utils_begin(T) + +`define uvm_component_utils_end \ + `uvm_field_utils_end + + +// MACRO -- NODOCS -- `uvm_object_registry +// +// Register a uvm_object-based class with the factory +// +//| `uvm_object_registry(T,S) +// +// Registers a uvm_object-based class ~T~ and lookup +// string ~S~ with the factory. ~S~ typically is the +// name of the class in quotes. The <`uvm_object_utils> +// family of macros uses this macro. + +`define uvm_object_registry(T,S) \ + typedef uvm_object_registry#(T,S) type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + + +// MACRO -- NODOCS -- `uvm_component_registry +// +// Registers a uvm_component-based class with the factory +// +//| `uvm_component_registry(T,S) +// +// Registers a uvm_component-based class ~T~ and lookup +// string ~S~ with the factory. ~S~ typically is the +// name of the class in quotes. The <`uvm_object_utils> +// family of macros uses this macro. + +`define uvm_component_registry(T,S) \ + typedef uvm_component_registry #(T,S) type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + + +`define uvm_declare_type_alias(TYPE,NAME,SFX=) \ + static bit m__alias_declared``SFX = TYPE::type_id::set_type_alias(NAME); + + +// uvm_new_func +// ------------ + +`define uvm_new_func \ + function new (string name, uvm_component parent); \ + super.new(name, parent); \ + endfunction + + +//----------------------------------------------------------------------------- +// INTERNAL MACROS - in support of *_utils macros -- do not use directly +//----------------------------------------------------------------------------- + +// m_uvm_object_create_func +// ------------------------ + +`define m_uvm_object_create_func(T) \ + function uvm_object create (string name=""); \ + T tmp; \ + if (name=="") tmp = new(); \ + else tmp = new(name); \ + return tmp; \ + endfunction + +// Macro --NODOCS-- uvm_type_name_decl(TNAME_STRING) +// Potentially public macro for Mantis 5003. +// +// This macro creates a statically accessible +// ~type_name~, and implements the virtual +// method. +// +// *Note:* When running with <`UVM_ENABLE_DEPRECATED_API>, +// the ~type_name~ member is declared as: +//| const static string type_name = TNAME_STRING; +// This is unsafe, as static initialization can cause races +// to occur. When running without <`UVM_ENABLE_DEPRECATED_API>, +// the implementation is an static initialization safe function: +//| static function string type_name(); +//| return TNAME_STRING; +//| endfunction : type_name +// +`ifdef UVM_ENABLE_DEPRECATED_API + `define uvm_type_name_decl(TNAME_STRING) \ + const static string type_name = TNAME_STRING; \ + virtual function string get_type_name(); \ + return TNAME_STRING; \ + endfunction : get_type_name +`else + `define uvm_type_name_decl(TNAME_STRING) \ + static function string type_name(); \ + return TNAME_STRING; \ + endfunction : type_name \ + virtual function string get_type_name(); \ + return TNAME_STRING; \ + endfunction : get_type_name +`endif // !`ifdef UVM_ENABLE_DEPRECATED_API + + +// m_uvm_object_registry_internal +// ------------------------------ + +//This is needed due to an issue in of passing down strings +//created by args to lower level macros. +`define m_uvm_object_registry_internal(T,S) \ + typedef uvm_object_registry#(T,`"S`") type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + + +// m_uvm_object_registry_param +// --------------------------- + +`define m_uvm_object_registry_param(T) \ + typedef uvm_object_registry #(T) type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + +// m_uvm_object_abstract_registry_internal +// --------------------------------------- + +//This is needed due to an issue in of passing down strings +//created by args to lower level macros. +`define m_uvm_object_abstract_registry_internal(T,S) \ + typedef uvm_abstract_object_registry#(T,`"S`") type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + + +// m_uvm_object_abstract_registry_param +// ------------------------------------ + +`define m_uvm_object_abstract_registry_param(T) \ + typedef uvm_abstract_object_registry #(T) type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + + +// m_uvm_component_registry_internal +// --------------------------------- + +//This is needed due to an issue in of passing down strings +//created by args to lower level macros. +`define m_uvm_component_registry_internal(T,S) \ + typedef uvm_component_registry #(T,`"S`") type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + +// versions of the uvm_component_registry macros to be used with +// parameterized classes + +// m_uvm_component_registry_param +// ------------------------------ + +`define m_uvm_component_registry_param(T) \ + typedef uvm_component_registry #(T) type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + +// m_uvm_component_abstract_registry_internal +// ------------------------------------------ + +//This is needed due to an issue in of passing down strings +//created by args to lower level macros. +`define m_uvm_component_abstract_registry_internal(T,S) \ + typedef uvm_abstract_component_registry #(T,`"S`") type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + +// versions of the uvm_component_abstract_registry macros to be used with +// parameterized classes + +// m_uvm_component_abstract_registry_param +// --------------------------------------- + +`define m_uvm_component_abstract_registry_param(T) \ + typedef uvm_abstract_component_registry #(T) type_id; \ + static function type_id get_type(); \ + return type_id::get(); \ + endfunction \ + virtual function uvm_object_wrapper get_object_type(); \ + return type_id::get(); \ + endfunction + + + +//------------------------------------------------------------------------------ +// +// Group -- NODOCS -- Field Macros +// +// The `uvm_field_* macros are invoked inside of the `uvm_*_utils_begin and +// `uvm_*_utils_end macro blocks to form "automatic" implementations of the +// core data methods: copy, compare, pack, unpack, record, print, and sprint. +// +// By using the macros, you do not have to implement any of the do_* methods +// inherited from . However, be aware that the field macros expand +// into general inline code that is not as run-time efficient nor as flexible +// as direct implementations of the do_* methods. +// +// Below is an example usage of the field macros for a sequence item. +// +//| class my_trans extends uvm_sequence_item; +//| +//| cmd_t cmd; +//| int addr; +//| int data[$]; +//| my_ext ext; +//| string str; +//| +//| `uvm_object_utils_begin(my_trans) +//| `uvm_field_enum (cmd_t, cmd, UVM_ALL_ON) +//| `uvm_field_int (addr, UVM_ALL_ON) +//| `uvm_field_queue_int(data, UVM_ALL_ON) +//| `uvm_field_object (ext, UVM_ALL_ON) +//| `uvm_field_string (str, UVM_ALL_ON) +//| `uvm_object_utils_end +//| +//| function new(string name="mydata_inst"); +//| super.new(name); +//| endfunction +//| +//| endclass +// +// Below is an example usage of the field macros for a component. +// +//| class my_comp extends uvm_component; +//| +//| my_comp_cfg cfg; +//| +//| `uvm_component_utils_begin(my_comp) +//| `uvm_field_object (cfg, UVM_ALL_ON) +//| `uvm_object_utils_end +//| +//| function new(string name="my_comp_inst", uvm_component parent=null); +//| super.new(name); +//| endfunction +//| +//| endclass +// +// Each `uvm_field_* macro is named according to the particular data type it +// handles: integrals, strings, objects, queues, etc., and each has at least two +// arguments: ~ARG~ and ~FLAG~. +// +// ARG - is the instance name of the variable, whose type must be compatible with +// the macro being invoked. In the example, class variable ~addr~ is an integral type, +// so we use the ~`uvm_field_int~ macro. +// +// FLAG - if set to ~UVM_ALL_ON~, as in the example, the ARG variable will be +// included in all data methods. If FLAG is set to something other than +// ~UVM_ALL_ON~ or ~UVM_DEFAULT~, it specifies which data method implementations will +// ~not~ include the given variable. Thus, if ~FLAG~ is specified as ~NO_COMPARE~, +// the ARG variable will not affect comparison operations, but it will be +// included in everything else. +// +// All possible values for ~FLAG~ are listed and described below. Multiple flag +// values can be bitwise OR'ed together (in most cases they may be added together +// as well, but care must be taken when using the + operator to ensure that the +// same bit is not added more than once). +// +// UVM_ALL_ON - Set all operations on. +// UVM_DEFAULT - This is the recommended set of flags to pass +// to the field macros. Currently, it enables +// all of the operations, making it functionally +// identical to ~UVM_ALL_ON~. In the future +// however, additional flags could be added with +// a recommended default value of ~off~. +// +// UVM_NOCOPY - Do not copy this field. +// UVM_NOCOMPARE - Do not compare this field. +// UVM_NOPRINT - Do not print this field. +// UVM_NOPACK - Do not pack or unpack this field. +// +// UVM_REFERENCE - For object types, operate only on the handle (e.g. no deep copy) +// +// UVM_PHYSICAL - Treat as a physical field. Use physical setting in +// policy class for this field. +// UVM_ABSTRACT - Treat as an abstract field. Use the abstract setting +// in the policy class for this field. +// UVM_READONLY - Do not allow setting of this field from the set_*_local +// methods or during operation. +// +// +// A radix for printing and recording can be specified by OR'ing one of the +// following constants in the ~FLAG~ argument +// +// UVM_BIN - Print / record the field in binary (base-2). +// UVM_DEC - Print / record the field in decimal (base-10). +// UVM_UNSIGNED - Print / record the field in unsigned decimal (base-10). +// UVM_OCT - Print / record the field in octal (base-8). +// UVM_HEX - Print / record the field in hexadecimal (base-16). +// UVM_STRING - Print / record the field in string format. +// UVM_TIME - Print / record the field in time format. +// +// Radix settings for integral types. Hex is the default radix if none is +// specified. +// +// A UVM component should ~not~ be specified using the `uvm_field_object macro +// unless its flag includes UVM_REFERENCE. Otherwise, the field macro will +// implement deep copy, which is an illegal operation for uvm_components. +// You will get a FATAL error if you tried to copy or clone an object containing +// a component handle that was registered with a field macro without the +// UVM_REFERENCE flag. You will also get duplicate entries when printing +// component topology, as this functionality is already provided by UVM. +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +// Group -- NODOCS -- `uvm_field_* macros +// +// Macros that implement data operations for scalar properties. +// +//----------------------------------------------------------------------------- + +// The m_uvm_* macros are implementation artifacts. They are not intended to be +// directly used by the user. + +`define m_uvm_field_radix(FLAG) uvm_radix_enum'((FLAG)&(UVM_RADIX)) + +`define m_uvm_field_recursion(FLAG) uvm_recursion_policy_enum'((FLAG)&(UVM_RECURSION)) + +`define m_uvm_field_begin(ARG, FLAG) \ + begin \ + case (local_op_type__) + +`define m_uvm_field_end(ARG) \ + endcase \ + end + + +`define m_uvm_field_op_begin(OP, FLAG) \ +UVM_``OP: \ + if (!((FLAG)&UVM_NO``OP)) begin + +`define m_uvm_field_op_end(OP) \ + end + +// MACRO -- NODOCS -- `uvm_field_int +// +// Implements the data operations for any packed integral property. +// +//| `uvm_field_int(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is an integral property of the class, and ~FLAG~ is a bitwise OR of +// one or more flag settings as described in above. + +`define uvm_field_int(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_int(ARG, local_rhs__.ARG, `m_uvm_field_radix(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_int(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_int(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_int(`"ARG`", \ + ARG, \ + $bits(ARG), \ + `m_uvm_field_radix(FLAG), \ + __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_int(ARG, $bits(ARG), `m_uvm_field_radix(FLAG),,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + ARG, \ + this) \ + /* TODO if(local_success__ && printing matches) */ \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// MACRO -- NODOCS -- `uvm_field_object +// +// Implements the data operations for a -based property. +// +//| `uvm_field_object(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is an object property of the class, and ~FLAG~ is a bitwise OR of +// one or more flag settings as described in above. + +`define uvm_field_object(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + `uvm_copy_object(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_copier__) \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_object(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + `uvm_pack_object(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + `uvm_unpack_object(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + __local_recorder__.record_object(`"ARG`", ARG); \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_object(ARG, `m_uvm_field_recursion(FLAG),__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + uvm_object, \ + local_obj__, \ + this) \ + if (local_success__) begin \ + if (local_obj__ == null) begin \ + ARG = null; \ + end else if (!$cast(ARG, local_obj__)) begin \ + `uvm_warning("UVM/FIELDS/OBJ_TYPE", $sformatf("Can't set field '%s' on '%s' with '%s' type", \ + `"ARG`", \ + this.get_full_name(), \ + local_obj__.get_type_name())) \ + end \ + /* TODO if(local_success__ && printing matches) */ \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_string +// +// Implements the data operations for a string property. +// +//| `uvm_field_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a string property of the class, and ~FLAG~ is a bitwise OR of +// one or more flag settings as described in above. + +`define uvm_field_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_string(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_string(`"ARG`", ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + __local_printer__.print_string(`"ARG`", ARG); \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + string, \ + ARG, \ + this) \ + /* TODO if(local_success__ && printing matches) */ \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_enum +// +// Implements the data operations for an enumerated property. +// +//| `uvm_field_enum(T,ARG,FLAG=UVM_DEFAULT) +// +// ~T~ is an enumerated _type_, ~ARG~ is an instance of that type, and +// ~FLAG~ is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_enum(T,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_enum(ARG, local_rhs__.ARG, T, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_enum(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_enum(ARG, T, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_enum(`"ARG`", ARG, T, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + if (`m_uvm_field_radix(FLAG) inside {UVM_NORADIX, UVM_ENUM, UVM_STRING}) \ + `uvm_print_enum(T, ARG,__local_printer__) \ + else \ + `uvm_print_int(ARG, $bits(ARG), `m_uvm_field_radix(FLAG),T,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_enum_read(local_success__, \ + local_rsrc__, \ + T, \ + ARG, \ + this) \ + /* TODO if(local_success__ && printing matches) */ \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_real +// +// Implements the data operations for any real property. +// +//| `uvm_field_real(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is an real property of the class, and ~FLAG~ is a bitwise OR of +// one or more flag settings as described in above. + +`define uvm_field_real(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_real(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_real(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_real(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_real(`"ARG`", ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + __local_printer__.print_real(`"ARG`", ARG); \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_real_read(local_success__, \ + local_rsrc__, \ + ARG, \ + this) \ + /* TODO if(local_success__ && printing matches) */ \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// MACRO -- NODOCS -- `uvm_field_event +// +// Implements the data operations for an event property. +// +//| `uvm_field_event(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is an event property of the class, and ~FLAG~ is a bitwise OR of +// one or more flag settings as described in above. + +`define uvm_field_event(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `m_uvm_compare_begin(ARG, local_rhs__.ARG, __local_comparer__) \ + __local_comparer__.print_msg({`"ARG`", " event miscompare"}); \ + `m_uvm_compare_end \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + __local_printer__.print_generic(`"ARG`", "event", -1, ""); \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +//----------------------------------------------------------------------------- +// Group -- NODOCS -- `uvm_field_sarray_* macros +// +// Macros that implement data operations for one-dimensional static array +// properties. +//----------------------------------------------------------------------------- + +// MACRO -- NODOCS -- `uvm_field_sarray_int +// +// Implements the data operations for a one-dimensional static array of +// integrals. +// +//| `uvm_field_sarray_int(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional static array of integrals, and ~FLAG~ +// is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_sarray_int(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_sarray_int(ARG, local_rhs__.ARG, `m_uvm_field_radix(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_sarray(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_sarray(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_int(ARG, `m_uvm_field_radix(FLAG), __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_sarray_int(ARG, \ + `m_uvm_field_radix(FLAG),, \ + __local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if ((local_index__ >= $size(ARG)) || (local_index__ < 0)) begin \ + `uvm_warning("UVM/FIELDS/SARRAY_IDX", $sformatf("Index '%d' is not valid for static array '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + $size(ARG))) \ + end \ + else begin \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_sarray_object +// +// Implements the data operations for a one-dimensional static array of +// -based objects. +// +//| `uvm_field_sarray_object(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional static array of -based objects, +// and ~FLAG~ is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_sarray_object(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + foreach(ARG[i]) begin \ + `uvm_copy_object(ARG[i], local_rhs__.ARG[i], `m_uvm_field_recursion(FLAG), __local_copier__) \ + end \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_sarray_object(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + foreach(ARG[i]) \ + `uvm_pack_object(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + foreach(ARG[i]) \ + `uvm_unpack_object(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_object(ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_sarray_object(ARG, `m_uvm_field_recursion(FLAG), __local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if ((local_index__ >= $size(ARG)) || (local_index__ < 0)) begin \ + `uvm_warning("UVM/FIELDS/SARRAY_IDX", $sformatf("Index '%d' is not valid for static array '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + $size(ARG))) \ + end \ + else begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + uvm_object, \ + local_obj__, \ + this) \ + if (local_success__) begin \ + if (local_obj__ == null) begin \ + ARG[local_index__] = null; \ + end else if (!$cast(ARG[local_index__], local_obj__)) begin \ + `uvm_warning("UVM/FIELDS/OBJ_TYPE", $sformatf("Can't set field '%s[%d]' on '%s' with '%s' type", \ + `"ARG`", \ + local_index__, \ + this.get_full_name(), \ + local_obj__.get_type_name())) \ + end \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_sarray_string +// +// Implements the data operations for a one-dimensional static array of +// strings. +// +//| `uvm_field_sarray_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional static array of strings, and ~FLAG~ is a bitwise +// OR of one or more flag settings as described in above. + +`define uvm_field_sarray_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_sarray_string(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + foreach(ARG[i]) \ + `uvm_pack_string(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + foreach(ARG[i]) \ + `uvm_unpack_string(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_string(ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_sarray_string(ARG,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if ((local_index__ >= $size(ARG)) || (local_index__ < 0)) begin \ + `uvm_warning("UVM/FIELDS/SARRAY_IDX", $sformatf("Index '%d' is not valid for static array '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + $size(ARG))) \ + end \ + else begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + string, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_sarray_enum +// +// Implements the data operations for a one-dimensional static array of +// enums. +// +//| `uvm_field_sarray_enum(T,ARG,FLAG=UVM_DEFAULT) +// +// ~T~ is a one-dimensional dynamic array of enums _type_, ~ARG~ is an +// instance of that type, and ~FLAG~ is a bitwise OR of one or more flag +// settings as described in above. + +`define uvm_field_sarray_enum(T,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_sarray_enum(ARG, local_rhs__.ARG, T, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + foreach (ARG[i]) \ + `uvm_pack_enumN(ARG[i], $bits(T), __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + foreach (ARG[i]) \ + `uvm_unpack_enumN(ARG[i], $bits(T), T, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_enum(ARG, T, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_sarray_enum(T, ARG ,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if ((local_index__ >= $size(ARG)) || (local_index__ < 0)) begin \ + `uvm_warning("UVM/FIELDS/SARRAY_IDX", $sformatf("Index '%d' is not valid for static array '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + $size(ARG))) \ + end \ + else begin \ + `uvm_resource_enum_read(local_success__, \ + local_rsrc__, \ + T, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +//----------------------------------------------------------------------------- +// Group -- NODOCS -- `uvm_field_array_* macros +// +// Macros that implement data operations for one-dimensional dynamic array +// properties. +// +// Implementation note: +// lines flagged with empty multi-line comments, /**/, are not needed or need +// to be different for fixed arrays, which cannot be resized. Fixed arrays +// do not need to pack/unpack their size either, because their size is known; +// wouldn't hurt though if it allowed code consolidation. Unpacking would +// necessarily be different. */ +// +//----------------------------------------------------------------------------- + + +// m_uvm_QUEUE_resize +// ------------------ + +`define m_uvm_queue_resize(ARG, SZ) \ + if (ARG.size() > SZ) \ + ARG = ARG[0:SZ-1]; \ + else \ + while (ARG.size() < SZ) ARG.push_back(ARG[SZ]); + +// m_uvm_da_resize +// ------------------ + +`define m_uvm_da_resize(ARG, SZ) \ + if (ARG.size() != SZ) ARG = new[SZ](ARG); + + +// m_uvm_field_qda_int +// ------------------- + +`define m_uvm_field_qda_int(TYPE,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_qda_int(ARG, local_rhs__.ARG, `m_uvm_field_radix(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_``TYPE``(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_``TYPE``(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_int(ARG, `m_uvm_field_radix(FLAG), __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_qda_int(TYPE, ARG, `m_uvm_field_radix(FLAG),,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + local_size__, \ + this) \ + if (local_success__) \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if (local_index__ < 0) begin \ + `uvm_warning("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + ARG.size() ) ) \ + end \ + else begin \ + bit tmp_stream__[]; \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + { << bit { tmp_stream__ }}, \ + this) \ + if (local_success__) begin \ + if (local_index__ >= ARG.size()) \ + `m_uvm_``TYPE``_resize(ARG, local_index__ + 1) \ + tmp_stream__ = new[$bits(ARG[local_index__])] (tmp_stream__); \ + ARG[local_index__] = { << bit { tmp_stream__ }}; \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// MACRO -- NODOCS -- `uvm_field_array_int +// +// Implements the data operations for a one-dimensional dynamic array of +// integrals. +// +//| `uvm_field_array_int(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional dynamic array of integrals, +// and ~FLAG~ is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_array_int(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_int(da,ARG,FLAG) + +`define m_uvm_field_qda_object(TYPE,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + if ((`m_uvm_field_recursion(FLAG) == UVM_REFERENCE) || !local_rhs__.ARG.size()) \ + ARG = local_rhs__.ARG; \ + else begin \ + `m_uvm_``TYPE``_resize(ARG, local_rhs__.ARG.size()) \ + foreach (ARG[i]) \ + `uvm_copy_object(ARG[i], local_rhs__.ARG[i], `m_uvm_field_recursion(FLAG), __local_copier__) \ + end \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_qda_object(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + __local_packer__.pack_field_int(ARG.size(), 32); \ + foreach (ARG[i]) \ + `uvm_pack_object(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + local_size__ = __local_packer__.unpack_field_int(32); \ + `m_uvm_``TYPE``_resize(ARG, local_size__); \ + foreach (ARG[i]) \ + `uvm_unpack_object(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_object(ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_qda_object(TYPE, ARG, `m_uvm_field_recursion(FLAG),__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + local_size__, \ + this) \ + if (local_success__) \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if (local_index__ < 0) begin \ + `uvm_warning("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + ARG.size() ) ) \ + end \ + else begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + uvm_object, \ + local_obj__, \ + this) \ + if (local_success__) begin \ + if (local_index__ >= ARG.size()) \ + `m_uvm_``TYPE``_resize(ARG, local_index__ + 1) \ + if (local_obj__ == null) begin \ + ARG[local_index__] = null; \ + end else if (!$cast(ARG[local_index__], local_obj__)) begin \ + `uvm_error("UVM/FIELDS/QDA_OBJ_TYPE", \ + $sformatf("Can't set field '%s[%0d]' on '%s' with '%s' type", \ + `"ARG`", \ + local_index__, \ + this.get_full_name(), \ + local_obj__.get_type_name())) \ + end \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// MACRO -- NODOCS -- `uvm_field_array_object +// +// Implements the data operations for a one-dimensional dynamic array +// of -based objects. +// +//| `uvm_field_array_object(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional dynamic array of -based objects, +// and ~FLAG~ is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_array_object(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_object(da,ARG,FLAG) + + + +// MACRO -- NODOCS -- `uvm_field_array_string +// +// Implements the data operations for a one-dimensional dynamic array +// of strings. +// +//| `uvm_field_array_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional dynamic array of strings, and ~FLAG~ is a bitwise +// OR of one or more flag settings as described in above. + +`define uvm_field_array_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_string(da,ARG,FLAG) + +`define m_uvm_field_qda_string(TYPE,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_qda_string(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + __local_packer__.pack_field_int(ARG.size(), 32); \ + foreach (ARG[i]) \ + `uvm_pack_string(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + local_size__ = __local_packer__.unpack_field_int(32); \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + foreach (ARG[i]) \ + `uvm_unpack_string(ARG[i], __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_string(ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_qda_string(TYPE, ARG,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + local_size__, \ + this) \ + if (local_success__) \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if (local_index__ < 0) begin \ + `uvm_warning("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + ARG.size() ) ) \ + end \ + else begin \ + string tmp_string__; \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + string, \ + tmp_string__, \ + this) \ + if (local_success__) begin \ + if (local_index__ >= ARG.size()) \ + `m_uvm_``TYPE``_resize(ARG, local_index__ + 1) \ + ARG[local_index__] = tmp_string__; \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// MACRO -- NODOCS -- `uvm_field_array_enum +// +// Implements the data operations for a one-dimensional dynamic array of +// enums. +// +//| `uvm_field_array_enum(T,ARG,FLAG=UVM_DEFAULT) +// +// ~T~ is a one-dimensional dynamic array of enums _type_, +// ~ARG~ is an instance of that type, and ~FLAG~ is a bitwise OR of +// one or more flag settings as described in above. + +`define uvm_field_array_enum(T,ARG,FLAG=UVM_DEFAULT) \ + `m_field_qda_enum(da,T,ARG,FLAG) + +`define m_field_qda_enum(TYPE,T,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_qda_enum(ARG, local_rhs__.ARG, T, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + __local_packer__.pack_field_int(ARG.size(), 32); \ + foreach (ARG[i]) \ + `uvm_pack_enumN(ARG[i], $bits(T), __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + local_size__ = __local_packer__.unpack_field_int(32); \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + foreach (ARG[i]) \ + `uvm_unpack_enumN(ARG[i], $bits(T), T, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_enum(ARG, T, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_qda_enum(TYPE, T, ARG,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + local_size__, \ + this) \ + if (local_success__) \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if (local_index__ < 0) begin \ + `uvm_warning("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + ARG.size() ) ) \ + end \ + else begin \ + T tmp_enum__; \ + `uvm_resource_enum_read(local_success__, \ + local_rsrc__, \ + T, \ + tmp_enum__, \ + this) \ + if (local_success__) begin \ + if (local_index__ >= ARG.size()) \ + `m_uvm_``TYPE``_resize(ARG, local_index__ + 1) \ + ARG[local_index__] = tmp_enum__; \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +//----------------------------------------------------------------------------- +// Group -- NODOCS -- `uvm_field_queue_* macros +// +// Macros that implement data operations for dynamic queues. +// +//----------------------------------------------------------------------------- + +// MACRO -- NODOCS -- `uvm_field_queue_int +// +// Implements the data operations for a queue of integrals. +// +//| `uvm_field_queue_int(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional queue of integrals, +// and ~FLAG~ is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_queue_int(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_int(queue,ARG,FLAG) + +// MACRO -- NODOCS -- `uvm_field_queue_object +// +// Implements the data operations for a queue of -based objects. +// +//| `uvm_field_queue_object(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional queue of -based objects, +// and ~FLAG~ is a bitwise OR of one or more flag settings as described in +// above. + +`define uvm_field_queue_object(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_object(queue,ARG,FLAG) + + +// MACRO -- NODOCS -- `uvm_field_queue_string +// +// Implements the data operations for a queue of strings. +// +//| `uvm_field_queue_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is a one-dimensional queue of strings, and ~FLAG~ is a bitwise +// OR of one or more flag settings as described in above. + +`define uvm_field_queue_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_string(queue,ARG,FLAG) + + +// MACRO -- NODOCS -- `uvm_field_queue_enum +// +// Implements the data operations for a one-dimensional queue of enums. +// +//| `uvm_field_queue_enum(T,ARG,FLAG=UVM_DEFAULT) +// +// ~T~ is a queue of enums _type_, ~ARG~ is an instance of that type, +// and ~FLAG~ is a bitwise OR of one or more flag settings as described +// in above. + +`define uvm_field_queue_enum(T,ARG,FLAG=UVM_DEFAULT) \ + `m_field_qda_enum(queue,T,ARG,FLAG) + + +//----------------------------------------------------------------------------- +// Group -- NODOCS -- `uvm_field_aa_*_string macros +// +// Macros that implement data operations for associative arrays indexed +// by ~string~. +// +//----------------------------------------------------------------------------- + +// MACRO -- NODOCS -- `uvm_field_aa_int_string +// +// Implements the data operations for an associative array of integrals indexed +// by ~string~. +// +//| `uvm_field_aa_int_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with string key, and ~FLAG~ is a bitwise OR of one or more flag settings as +// described in above. + +`define uvm_field_aa_int_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_int_string(ARG, local_rhs__.ARG, `m_uvm_field_radix(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_aa_int_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_aa_int_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_aa_int_string(ARG, `m_uvm_field_radix(FLAG), int, __local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/AA_SIZE", $sformatf("Associative array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + `uvm_resource_builtin_int_read(local_success__, \ + local_rsrc__, \ + ARG[local_index__], \ + this) \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_aa_object_string +// +// Implements the data operations for an associative array of -based +// objects indexed by ~string~. +// +//| `uvm_field_aa_object_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of objects +// with string key, and ~FLAG~ is a bitwise OR of one or more flag settings as +// described in above. + +`define uvm_field_aa_object_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + `uvm_copy_aa_object(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_copier__) \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_object_string(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + `uvm_pack_aa_object_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + `uvm_unpack_aa_object_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_aa_object_string(ARG, `m_uvm_field_recursion(FLAG),__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/AA_SIZE", $sformatf("Associative array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + uvm_object, \ + local_obj__, \ + this) \ + if (local_success__) begin \ + if (local_obj__ == null) begin \ + ARG[local_index__] = null; \ + end else if (!$cast(ARG[local_index__], local_obj__)) begin \ + `uvm_warning("UVM/FIELDS/OBJ_TYPE", $sformatf("Can't set field '%s[%s]' on '%s' with '%s' type", \ + `"ARG`", \ + local_index__, \ + this.get_full_name(), \ + local_obj__.get_type_name())) \ + end \ + end \ + /* TODO if(local_success__ && printing matches) */ \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_aa_string_string +// +// Implements the data operations for an associative array of strings indexed +// by ~string~. +// +//| `uvm_field_aa_string_string(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of strings +// with string key, and ~FLAG~ is a bitwise OR of one or more flag settings as +// described in above. + +`define uvm_field_aa_string_string(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_string_string(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_aa_string_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_aa_string_string(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_aa_string_string(ARG,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/AA_SIZE", $sformatf("Associative array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + string, \ + ARG[local_index__], \ + this) \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +//----------------------------------------------------------------------------- +// Group -- NODOCS -- `uvm_field_aa_*_int macros +// +// Macros that implement data operations for associative arrays indexed by an +// integral type. +// +//----------------------------------------------------------------------------- + +// MACRO -- NODOCS -- `uvm_field_aa_object_int +// +// Implements the data operations for an associative array of -based +// objects indexed by the ~int~ data type. +// +//| `uvm_field_aa_object_int(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of objects +// with ~int~ key, and ~FLAG~ is a bitwise OR of one or more flag settings as +// described in above. + +`define uvm_field_aa_object_int(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_object_key(int, ARG, FLAG) + +// Not LRM, but supports packing + configuration +`define uvm_field_aa_object_key(KEY, ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + `uvm_copy_aa_object(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_copier__) \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_object_int(ARG, local_rhs__.ARG, `m_uvm_field_recursion(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + `uvm_pack_aa_object_intN(ARG, $bits(KEY), __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + if (`m_uvm_field_recursion(FLAG) != UVM_REFERENCE) \ + `uvm_unpack_aa_object_intN(ARG, $bits(KEY), __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_aa_object_int(ARG, `m_uvm_field_recursion(FLAG), KEY,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + KEY local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + uvm_object, \ + local_obj__, \ + this) \ + if (local_success__) begin \ + if (local_obj__ == null) begin \ + ARG[local_index__] = null; \ + end else if (!$cast(ARG[local_index__], local_obj__)) begin \ + `uvm_warning("UVM/FIELDS/OBJ_TYPE", $sformatf("Can't set field '%s[%d]' on '%s' with '%s' type", \ + `"ARG`", \ + local_index__, \ + this.get_full_name(), \ + local_obj__.get_type_name())) \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// Not LRM, oversight? +`define uvm_field_aa_string_int(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_string_key(int, ARG, FLAG) + +// Not LRM, but supports packing + configuration +`define uvm_field_aa_string_key(KEY, ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_string_int(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_aa_string_intN(ARG, $bits(KEY), __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_aa_string_intN(ARG, $bits(KEY), __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + /* TODO */ \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + KEY local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + `uvm_resource_read(local_success__, \ + local_rsrc__, \ + string, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// MACRO -- NODOCS -- `uvm_field_aa_int_int +// +// Implements the data operations for an associative array of integral +// types indexed by the ~int~ data type. +// +//| `uvm_field_aa_int_int(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~int~ key, and ~FLAG~ is a bitwise OR of one or more flag settings as +// described in above. + +`define uvm_field_aa_int_int(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(int, ARG, FLAG) \ + + +// MACRO -- NODOCS -- `uvm_field_aa_int_int_unsigned +// +// Implements the data operations for an associative array of integral +// types indexed by the ~int unsigned~ data type. +// +//| `uvm_field_aa_int_int_unsigned(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~int unsigned~ key, and ~FLAG~ is a bitwise OR of one or more flag +// settings as described in above. + +`define uvm_field_aa_int_int_unsigned(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(int unsigned, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_integer +// +// Implements the data operations for an associative array of integral +// types indexed by the ~integer~ data type. +// +//| `uvm_field_aa_int_integer(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~integer~ key, and ~FLAG~ is a bitwise OR of one or more flag settings +// as described in above. + +`define uvm_field_aa_int_integer(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(integer, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_integer_unsigned +// +// Implements the data operations for an associative array of integral +// types indexed by the ~integer unsigned~ data type. +// +//| `uvm_field_aa_int_integer_unsigned(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~integer unsigned~ key, and ~FLAG~ is a bitwise OR of one or more +// flag settings as described in above. + +`define uvm_field_aa_int_integer_unsigned(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(integer unsigned, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_byte +// +// Implements the data operations for an associative array of integral +// types indexed by the ~byte~ data type. +// +//| `uvm_field_aa_int_byte(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~byte~ key, and ~FLAG~ is a bitwise OR of one or more flag settings as +// described in above. + +`define uvm_field_aa_int_byte(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(byte, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_byte_unsigned +// +// Implements the data operations for an associative array of integral +// types indexed by the ~byte unsigned~ data type. +// +//| `uvm_field_aa_int_byte_unsigned(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~byte unsigned~ key, and ~FLAG~ is a bitwise OR of one or more flag +// settings as described in above. + +`define uvm_field_aa_int_byte_unsigned(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(byte unsigned, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_shortint +// +// Implements the data operations for an associative array of integral +// types indexed by the ~shortint~ data type. +// +//| `uvm_field_aa_int_shortint(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~shortint~ key, and ~FLAG~ is a bitwise OR of one or more flag +// settings as described in above. + +`define uvm_field_aa_int_shortint(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(shortint, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_shortint_unsigned +// +// Implements the data operations for an associative array of integral +// types indexed by the ~shortint unsigned~ data type. +// +//| `uvm_field_aa_int_shortint_unsigned(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~shortint unsigned~ key, and ~FLAG~ is a bitwise OR of one or more +// flag settings as described in above. + +`define uvm_field_aa_int_shortint_unsigned(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(shortint unsigned, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_longint +// +// Implements the data operations for an associative array of integral +// types indexed by the ~longint~ data type. +// +//| `uvm_field_aa_int_longint(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~longint~ key, and ~FLAG~ is a bitwise OR of one or more flag settings +// as described in above. + +`define uvm_field_aa_int_longint(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(longint, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_longint_unsigned +// +// Implements the data operations for an associative array of integral +// types indexed by the ~longint unsigned~ data type. +// +//| `uvm_field_aa_int_longint_unsigned(ARG,FLAG=UVM_DEFAULT) +// +// ~ARG~ is the name of a property that is an associative array of integrals +// with ~longint unsigned~ key, and ~FLAG~ is a bitwise OR of one or more +// flag settings as described in above. + +`define uvm_field_aa_int_longint_unsigned(ARG,FLAG=UVM_DEFAULT) \ + `uvm_field_aa_int_key(longint unsigned, ARG, FLAG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_key +// +// Implements the data operations for an associative array of integral +// types indexed by any integral key data type. +// +//| `uvm_field_aa_int_key(KEY,ARG,FLAG=UVM_DEFAULT) +// +// ~KEY~ is the data type of the integral key, ~ARG~ is the name of a property +// that is an associative array of integrals, and ~FLAG~ is a bitwise OR of one +// or more flag settings as described in above. + +`define uvm_field_aa_int_key(KEY, ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_int_int(ARG, local_rhs__.ARG, `m_uvm_field_radix(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_aa_int_intN(ARG, $bits(KEY), __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_aa_int_intN(ARG, $bits(KEY), __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_aa_int_int(ARG, `m_uvm_field_radix(FLAG), , KEY,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/AA_SIZE", $sformatf("Associative array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + KEY local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + `uvm_resource_int_read(local_success__, \ + local_rsrc__, \ + KEY, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + + +// MACRO -- NODOCS -- `uvm_field_aa_int_enumkey +// +// Implements the data operations for an associative array of integral +// types indexed by any enumeration key data type. +// +//| `uvm_field_aa_int_enumkey(KEY, ARG,FLAG=UVM_DEFAULT) +// +// ~KEY~ is the enumeration type of the key, ~ARG~ is the name of a property +// that is an associative array of integrals, and ~FLAG~ is a bitwise OR of one +// or more flag settings as described in above. + +`define uvm_field_aa_int_enumkey(KEY, ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG, FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + `uvm_compare_aa_int_int(ARG, local_rhs__.ARG, `m_uvm_field_radix(FLAG), __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_aa_int_enum(ARG, KEY, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_aa_int_enum(ARG, KEY, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_aa_int_enum(KEY, ARG, `m_uvm_field_radix(FLAG),,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/AA_SIZE", $sformatf("Associative array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + KEY local_index__; \ + bit[$bits(KEY)-1:0] local_bit_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_bit_index__); \ + if (local_code__ > 0) begin \ + local_index__ = KEY'(local_bit_index__); \ + `uvm_resource_int_read(local_success__, \ + local_rsrc__, \ + KEY, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +//-- Field Macros for arrays of real (Non-LRM enhancement) +`define uvm_field_sarray_real(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_sarray_real(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_sarray_real(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_sarray_real(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_real(ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_sarray_real(ARG,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_warning("UVM/FIELDS/SARRAY_SIZE", $sformatf("Static array '%s.%s' cannot be resized via configuration.", get_full_name(), `"ARG`") ) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if ((local_index__ >= $size(ARG)) || (local_index__ < 0)) begin \ + `uvm_warning("UVM/FIELDS/SARRAY_IDX", $sformatf("Index '%d' is not valid for static array '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + $size(ARG))) \ + end \ + else begin \ + `uvm_resource_real_read(local_success__, \ + local_rsrc__, \ + ARG[local_index__], \ + this) \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +// m_uvm_field_qda_real +// ------------------- + +`define m_uvm_field_qda_real(TYPE,ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_begin(ARG,FLAG) \ + `m_uvm_field_op_begin(COPY,FLAG) \ + ARG = local_rhs__.ARG; \ + `m_uvm_field_op_end(COPY) \ + `m_uvm_field_op_begin(COMPARE,FLAG) \ + if ((__local_comparer__.physical&&((FLAG)&UVM_PHYSICAL))|| \ + (__local_comparer__.abstract&&((FLAG)&UVM_ABSTRACT))|| \ + (!((FLAG)&UVM_PHYSICAL) && !((FLAG)&UVM_ABSTRACT))) \ + `uvm_compare_qda_real(ARG, local_rhs__.ARG, __local_comparer__) \ + `m_uvm_field_op_end(COMPARE) \ + `m_uvm_field_op_begin(PACK,FLAG) \ + `uvm_pack_``TYPE``_real(ARG, __local_packer__) \ + `m_uvm_field_op_end(PACK) \ + `m_uvm_field_op_begin(UNPACK,FLAG) \ + `uvm_unpack_``TYPE``_real(ARG, __local_packer__) \ + `m_uvm_field_op_end(UNPACK) \ + `m_uvm_field_op_begin(RECORD,FLAG) \ + `uvm_record_qda_real(ARG, __local_recorder__) \ + `m_uvm_field_op_end(RECORD) \ + `m_uvm_field_op_begin(PRINT,FLAG) \ + `uvm_print_qda_real(TYPE, ARG,__local_printer__) \ + `m_uvm_field_op_end(PRINT) \ + `m_uvm_field_op_begin(SET,FLAG) \ + if(local_rsrc_name__ == `"ARG`") begin \ + `uvm_resource_real_read(local_success__, \ + local_rsrc__, \ + local_size__, \ + this) \ + if (local_success__) \ + `m_uvm_``TYPE``_resize(ARG, local_size__) \ + end \ + else begin \ + string local_name__ = {`"ARG`", "["}; \ + if (local_rsrc_name__.len() && \ + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && \ + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin \ + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), \ + local_rsrc_name__.len()-2); \ + int local_index__; \ + /* TODO: Non-decimal indexes */ \ + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); \ + if (local_code__ > 0) begin \ + if (local_index__ < 0) begin \ + `uvm_warning("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", \ + local_index__, \ + get_full_name(), \ + `"ARG`", \ + ARG.size() ) ) \ + end \ + else begin \ + real tmp_real__; \ + `uvm_resource_real_read(local_success__, \ + local_rsrc__, \ + tmp_real__, \ + this) \ + if (local_success__) begin \ + if (local_index__ >= ARG.size()) \ + `m_uvm_``TYPE``_resize(ARG, local_index__ + 1) \ + ARG[local_index__] = tmp_real__; \ + end \ + end \ + end \ + end \ + end \ + `m_uvm_field_op_end(SET) \ + `m_uvm_field_end(ARG) + +`define uvm_field_array_real(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_real(da,ARG,FLAG) + +`define uvm_field_queue_real(ARG,FLAG=UVM_DEFAULT) \ + `m_uvm_field_qda_real(queue,ARG,FLAG) + +`endif // !`ifdef UVM_EMPTY_MACROS + +`endif // UVM_OBJECT_DEFINES_SVH diff --git a/test_regress/t/t_uvm/deprecated/macros/uvm_sequence_defines.svh b/test_regress/t/t_uvm/deprecated/macros/uvm_sequence_defines.svh new file mode 100644 index 0000000000..b90af51df2 --- /dev/null +++ b/test_regress/t/t_uvm/deprecated/macros/uvm_sequence_defines.svh @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2018 AMD +// Copyright 2018 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. +//------------------------------------------------------------------------------ + +// Title -- NODOCS -- Sequence-Related Macros + + + +//----------------------------------------------------------------------------- +// +// Group -- NODOCS -- Sequence Action Macros +// +// These macros are used to start sequences and sequence items on the default +// sequencer returned by get_sequencer(). This is determined a number of ways. +// - the sequencer handle provided in the method +// - the sequencer used by the parent sequence +// - the sequencer that was set using the method +//----------------------------------------------------------------------------- + + + +// MACRO -- NODOCS -- `uvm_do_pri +// +//| `uvm_do_pri(SEQ_OR_ITEM, PRIORITY) +// +// This is the same as `uvm_do except that the sequence item or sequence is +// executed with the priority specified in the argument + +`define uvm_do_pri(SEQ_OR_ITEM, PRIORITY) \ + `uvm_do(SEQ_OR_ITEM, get_sequencer(), PRIORITY, {}) + + +// MACRO -- NODOCS -- `uvm_do_with +// +//| `uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS) +// +// This is the same as `uvm_do except that the constraint block in the 2nd +// argument is applied to the item or sequence in a randomize with statement +// before execution. + +`define uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS) \ + `uvm_do(SEQ_OR_ITEM, get_sequencer(), -1, CONSTRAINTS) + + +// MACRO -- NODOCS -- `uvm_do_pri_with +// +//| `uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) +// +// This is the same as `uvm_do_pri except that the given constraint block is +// applied to the item or sequence in a randomize with statement before +// execution. + +`define uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) \ + `uvm_do(SEQ_OR_ITEM, get_sequencer(), PRIORITY, CONSTRAINTS) + + +//----------------------------------------------------------------------------- +// +// Group -- NODOCS -- Sequence on Sequencer Action Macros +// +// These macros are used to start sequences and sequence items on a specific +// sequencer. The sequence or item is created and executed on the given +// sequencer. +//----------------------------------------------------------------------------- + +// MACRO -- NODOCS -- `uvm_create_on +// +//| `uvm_create_on(SEQ_OR_ITEM, SEQR) +// +// This is the same as <`uvm_create> except that it also sets the parent sequence +// to the sequence in which the macro is invoked, and it sets the sequencer to +// the specified ~SEQR~ argument. + +`define uvm_create_on(SEQ_OR_ITEM, SEQR) \ + `uvm_create(SEQ_OR_ITEM, SEQR) + + +// MACRO -- NODOCS -- `uvm_do_on +// +//| `uvm_do_on(SEQ_OR_ITEM, SEQR) +// +// This is the same as <`uvm_do> except that it also sets the parent sequence to +// the sequence in which the macro is invoked, and it sets the sequencer to the +// specified ~SEQR~ argument. + +`define uvm_do_on(SEQ_OR_ITEM, SEQR) \ + `uvm_do(SEQ_OR_ITEM, SEQR, -1, {}) + + +// MACRO -- NODOCS -- `uvm_do_on_pri +// +//| `uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY) +// +// This is the same as <`uvm_do_pri> except that it also sets the parent sequence +// to the sequence in which the macro is invoked, and it sets the sequencer to +// the specified ~SEQR~ argument. + +`define uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY) \ + `uvm_do(SEQ_OR_ITEM, SEQR, PRIORITY, {}) + + +// MACRO -- NODOCS -- `uvm_do_on_with +// +//| `uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS) +// +// This is the same as <`uvm_do_with> except that it also sets the parent +// sequence to the sequence in which the macro is invoked, and it sets the +// sequencer to the specified ~SEQR~ argument. +// The user must supply brackets around the constraints. + +`define uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS) \ + `uvm_do(SEQ_OR_ITEM, SEQR, -1, CONSTRAINTS) + + +// MACRO -- NODOCS -- `uvm_do_on_pri_with +// +//| `uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) +// +// This is the same as `uvm_do_pri_with except that it also sets the parent +// sequence to the sequence in which the macro is invoked, and it sets the +// sequencer to the specified ~SEQR~ argument. + +`define uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) \ + `uvm_do(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) + + +//----------------------------------------------------------------------------- +// +// Group -- NODOCS -- Sequence Action Macros for Pre-Existing Sequences +// +// These macros are used to start sequences and sequence items that do not +// need to be created. +//----------------------------------------------------------------------------- + + + +// MACRO -- NODOCS -- `uvm_send_pri +// +//| `uvm_send_pri(SEQ_OR_ITEM, PRIORITY) +// +// This is the same as `uvm_send except that the sequence item or sequence is +// executed with the priority specified in the argument. + +`define uvm_send_pri(SEQ_OR_ITEM, PRIORITY) \ + `uvm_send(SEQ_OR_ITEM, PRIORITY) + + + +// MACRO -- NODOCS -- `uvm_rand_send_pri +// +//| `uvm_rand_send_pri(SEQ_OR_ITEM, PRIORITY) +// +// This is the same as `uvm_rand_send except that the sequence item or sequence +// is executed with the priority specified in the argument. + +`define uvm_rand_send_pri(SEQ_OR_ITEM, PRIORITY) \ + `uvm_rand_send(SEQ_OR_ITEM, PRIORITY, {}) + + +// MACRO -- NODOCS -- `uvm_rand_send_with +// +//| `uvm_rand_send_with(SEQ_OR_ITEM, CONSTRAINTS) +// +// This is the same as `uvm_rand_send except that the given constraint block is +// applied to the item or sequence in a randomize with statement before +// execution. + +`define uvm_rand_send_with(SEQ_OR_ITEM, CONSTRAINTS) \ + `uvm_rand_send(SEQ_OR_ITEM, -1, CONSTRAINTS) + + +// MACRO -- NODOCS -- `uvm_rand_send_pri_with +// +//| `uvm_rand_send_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) +// +// This is the same as `uvm_rand_send_pri except that the given constraint block +// is applied to the item or sequence in a randomize with statement before +// execution. + +`define uvm_rand_send_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) \ + `uvm_rand_send(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) + + +`define uvm_create_seq(UVM_SEQ, SEQR_CONS_IF) \ + `uvm_create(UVM_SEQ, SEQR_CONS_IF.consumer_seqr) \ + +`define uvm_do_seq(UVM_SEQ, SEQR_CONS_IF) \ + `uvm_do(UVM_SEQ, SEQR_CONS_IF.consumer_seqr, -1, {}) \ + +`define uvm_do_seq_with(UVM_SEQ, SEQR_CONS_IF, CONSTRAINTS) \ + `uvm_do(UVM_SEQ, SEQR_CONS_IF.consumer_seqr, -1, CONSTRAINTS) \ + diff --git a/test_regress/t/t_uvm/deprecated/readme.important b/test_regress/t/t_uvm/deprecated/readme.important new file mode 100644 index 0000000000..de4237c3fa --- /dev/null +++ b/test_regress/t/t_uvm/deprecated/readme.important @@ -0,0 +1,39 @@ +//---------------------------------------------------------------------- +// Copyright 2011 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2018 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. +//---------------------------------------------------------------------- + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + PLEASE NOTE: +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Files and Types, Classes, Functions etc within this directory are considered as +deprecated. By default, they are not included with the reference implementation. + +These files can be included by compiling with UVM_ENABLE_DEPRECATED_API defined. + +Usage of these files is not recommended, as: + +- they might be changed without any further notice in future versions of UVM +- they might be removed entirely in future versions of UVM +- they are not part of the UVM standard + + diff --git a/test_regress/t/t_uvm/dpi/uvm_common.c b/test_regress/t/t_uvm/dpi/uvm_common.c new file mode 100644 index 0000000000..4206a7c0f5 --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_common.c @@ -0,0 +1,52 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// 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. +//---------------------------------------------------------------------- + +// Implementation of common methods for DPI + +extern void m__uvm_report_dpi(int,const char*,const char*,int,const char*, int); + +#if defined(XCELIUM) || defined(NCSC) +const static char* uvm_package_scope_name = "uvm_pkg::"; +#else +const static char* uvm_package_scope_name = "uvm_pkg"; +#endif + +void m_uvm_report_dpi( int severity, + char* id, + char* message, + int verbosity, + char* file, + int linenum) { + svScope old_scope = svSetScope(svGetScopeFromName(uvm_package_scope_name)); + m__uvm_report_dpi(severity, id, message, verbosity, file, linenum); + svSetScope(old_scope); + } + + +int int_str_max ( int radix_bits ) { + int val = INT_MAX; + int ret = 1; + while ((val = (val /radix_bits))) + ret++; + return ret; +} diff --git a/test_regress/t/t_uvm/dpi/uvm_dpi.cc b/test_regress/t/t_uvm/dpi/uvm_dpi.cc new file mode 100644 index 0000000000..3112d3a111 --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_dpi.cc @@ -0,0 +1,64 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2017 Mentor Graphics Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- + +// +// Top-level file that includes all of the C/C++ files required +// by UVM +// +// The C code may be compiled by compiling this top file only, +// or by compiling individual files then linking them together. +// + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "uvm_dpi.h" + +// Avoid -Wmissing-definitions + int uvm_re_match(const char * re, const char *str); + const char * uvm_glob_to_re(const char *glob); + int uvm_hdl_check_path(char *path); + int uvm_hdl_read(char *path, p_vpi_vecval value); + int uvm_hdl_deposit(char *path, p_vpi_vecval value); + int uvm_hdl_force(char *path, p_vpi_vecval value); + int uvm_hdl_release_and_read(char *path, p_vpi_vecval value); + int uvm_hdl_release(char *path); + void push_data(int lvl,char *entry, int cmd); + void walk_level(int lvl, int argc, char**argv,int cmd); + const char *uvm_dpi_get_next_arg_c (int init); + extern char* uvm_dpi_get_tool_name_c (); + extern char* uvm_dpi_get_tool_version_c (); + extern regex_t* uvm_dpi_regcomp (char* pattern); + extern int uvm_dpi_regexec (regex_t* re, char* str); + extern void uvm_dpi_regfree (regex_t* re); + +#include "uvm_common.c" +#include "uvm_regex.cc" +#include "uvm_hdl.c" +#include "uvm_svcmd_dpi.c" + +#ifdef __cplusplus +} +#endif + diff --git a/test_regress/t/t_uvm/dpi/uvm_dpi.h b/test_regress/t/t_uvm/dpi/uvm_dpi.h new file mode 100644 index 0000000000..6ccee7da52 --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_dpi.h @@ -0,0 +1,84 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2017 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- + +// +// Top level header filke that wraps all requirements which +// are common to the various C/C++ files in UVM. +// + +#ifndef UVM_DPI__H +#define UVM_DPI__H + +#include +#include "vpi_user.h" +#include "veriuser.h" +#include "svdpi.h" +#include +#include +#include +#include +#include + +// The following consts and method call are for +// internal usage by the UVM DPI implementation, +// and are not intended for public use. +static const int M_UVM_INFO = 0; +static const int M_UVM_WARNING = 1; +static const int M_UVM_ERROR = 2; +static const int M_UVM_FATAL = 3; + +static const int M_UVM_NONE = 0; +static const int M_UVM_LOW = 100; +static const int M_UVM_MEDIUM = 200; +static const int M_UVM_HIGH = 300; +static const int M_UVM_FULL = 400; +static const int M_UVM_DEBUG = 500; + +void m_uvm_report_dpi(int severity, + char* id, + char* message, + int verbosity, + char* file, + int linenum); + +int int_str_max( int ); + +int uvm_re_match(const char * re, const char *str); +const char * uvm_glob_to_re(const char *glob); + +int uvm_hdl_check_path(char *path); +int uvm_hdl_read(char *path, p_vpi_vecval value); +int uvm_hdl_deposit(char *path, p_vpi_vecval value); +int uvm_hdl_force(char *path, p_vpi_vecval value); +int uvm_hdl_release_and_read(char *path, p_vpi_vecval value); +int uvm_hdl_release(char *path); + +void push_data(int lvl,char *entry, int cmd); +void walk_level(int lvl, int argc, char**argv,int cmd); +const char *uvm_dpi_get_next_arg_c (int init); +extern char* uvm_dpi_get_tool_name_c (); +extern char* uvm_dpi_get_tool_version_c (); +extern regex_t* uvm_dpi_regcomp (char* pattern); +extern int uvm_dpi_regexec (regex_t* re, char* str); +extern void uvm_dpi_regfree (regex_t* re); + +#endif diff --git a/test_regress/t/t_uvm/dpi/uvm_dpi.svh b/test_regress/t/t_uvm/dpi/uvm_dpi.svh new file mode 100644 index 0000000000..e89597f5e4 --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_dpi.svh @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// 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_DPI_SVH +`define UVM_DPI_SVH + +// +// Top-level file for DPI subroutines used by UVM. +// +// Tool-specific distribution overlays may be required. +// +// To use UVM without any tool-specific overlay, use +defin+UVM_NO_DPI +// + +`ifdef UVM_NO_DPI + `define UVM_HDL_NO_DPI + `define UVM_REGEX_NO_DPI + `define UVM_CMDLINE_NO_DPI +`endif + +`include "dpi/uvm_hdl.svh" +`include "dpi/uvm_svcmd_dpi.svh" +`include "dpi/uvm_regex.svh" + +`endif // UVM_DPI_SVH diff --git a/test_regress/t/t_uvm/dpi/uvm_hdl.c b/test_regress/t/t_uvm/dpi/uvm_hdl.c new file mode 100644 index 0000000000..b1730f3ae2 --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_hdl.c @@ -0,0 +1,37 @@ +//---------------------------------------------------------------------- +// Copyright 2009-2011 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- + +// hdl vendor backends are defined for VCS,QUESTA,XCELIUM +#if defined(VCS) || defined(VCSMX) +#include "uvm_hdl_vcs.c" +#else +#ifdef QUESTA +#include "uvm_hdl_questa.c" +#else +#if defined(XCELIUM) || defined(NCSC) +#include "uvm_hdl_xcelium.c" +#else +#error "hdl vendor backend is missing" +#endif +#endif +#endif + diff --git a/test_regress/t/t_uvm/dpi/uvm_hdl.svh b/test_regress/t/t_uvm/dpi/uvm_hdl.svh new file mode 100644 index 0000000000..0cadf9001c --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_hdl.svh @@ -0,0 +1,170 @@ +//------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2015 Analog Devices, Inc. +// Copyright 2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, Inc. +// Copyright 2012 Accellera Systems Initiative +// 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. +//------------------------------------------------------------ + +// TITLE -- NODOCS -- UVM HDL Backdoor Access support routines. +// +// These routines provide an interface to the DPI/PLI +// implementation of backdoor access used by registers. +// +// If you DON'T want to use the DPI HDL API, then compile your +// SystemVerilog code with the vlog switch +//: vlog ... +define+UVM_HDL_NO_DPI ... +// + + +`ifndef UVM_HDL__SVH +`define UVM_HDL__SVH + + +`ifndef UVM_HDL_MAX_WIDTH +// @uvm-ieee 1800.2-2017 auto 19.6.1 +`define UVM_HDL_MAX_WIDTH 1024 +`endif + +/* + * VARIABLE -- NODOCS -- UVM_HDL_MAX_WIDTH + * Sets the maximum size bit vector for backdoor access. + * This parameter will be looked up by the + * DPI-C code using: + * vpi_handle_by_name( + * "uvm_pkg::UVM_HDL_MAX_WIDTH", 0); + */ +parameter int UVM_HDL_MAX_WIDTH = `UVM_HDL_MAX_WIDTH; + + +typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t; + + +`ifndef UVM_HDL_NO_DPI + + // Function -- NODOCS -- uvm_hdl_check_path + // + // Checks that the given HDL ~path~ exists. Returns 0 if NOT found, 1 otherwise. + // + import "DPI-C" context function int uvm_hdl_check_path(string path); + + + // Function -- NODOCS -- uvm_hdl_deposit + // + // Sets the given HDL ~path~ to the specified ~value~. + // Returns 1 if the call succeeded, 0 otherwise. + // + import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value); + + + // Function -- NODOCS -- uvm_hdl_force + // + // Forces the ~value~ on the given ~path~. Returns 1 if the call succeeded, 0 otherwise. + // + import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value); + + + // Function -- NODOCS -- uvm_hdl_force_time + // + // Forces the ~value~ on the given ~path~ for the specified amount of ~force_time~. + // If ~force_time~ is 0, is called. + // Returns 1 if the call succeeded, 0 otherwise. + // + task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0); + if (force_time == 0) begin + void'(uvm_hdl_deposit(path, value)); + return; + end + if (!uvm_hdl_force(path, value)) + return; + #force_time; + void'(uvm_hdl_release_and_read(path, value)); + endtask + + + // Function -- NODOCS -- uvm_hdl_release_and_read + // + // Releases a value previously set with . + // Returns 1 if the call succeeded, 0 otherwise. ~value~ is set to + // the HDL value after the release. For 'reg', the value will still be + // the forced value until it has been procedurally reassigned. For 'wire', + // the value will change immediately to the resolved value of its + // continuous drivers, if any. If none, its value remains as forced until + // the next direct assignment. + // + import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value); + + + // Function -- NODOCS -- uvm_hdl_release + // + // Releases a value previously set with . + // Returns 1 if the call succeeded, 0 otherwise. + // + import "DPI-C" context function int uvm_hdl_release(string path); + + + // Function -- NODOCS -- uvm_hdl_read() + // + // Gets the value at the given ~path~. + // Returns 1 if the call succeeded, 0 otherwise. + // + import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value); + +`else + + function int uvm_hdl_check_path(string path); + uvm_report_fatal("UVM_HDL_CHECK_PATH", + $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI")); + return 0; + endfunction + + function int uvm_hdl_deposit(string path, uvm_hdl_data_t value); + uvm_report_fatal("UVM_HDL_DEPOSIT", + $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI")); + return 0; + endfunction + + function int uvm_hdl_force(string path, uvm_hdl_data_t value); + uvm_report_fatal("UVM_HDL_FORCE", + $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI")); + return 0; + endfunction + + task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time=0); + uvm_report_fatal("UVM_HDL_FORCE_TIME", + $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI")); + endtask + + function int uvm_hdl_release(string path, output uvm_hdl_data_t value); + uvm_report_fatal("UVM_HDL_RELEASE", + $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI")); + return 0; + endfunction + + function int uvm_hdl_read(string path, output uvm_hdl_data_t value); + uvm_report_fatal("UVM_HDL_READ", + $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI")); + return 0; + endfunction + +`endif + + +`endif diff --git a/test_regress/t/t_uvm/dpi/uvm_hdl_questa.c b/test_regress/t/t_uvm/dpi/uvm_hdl_questa.c new file mode 100644 index 0000000000..c81ed1519b --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_hdl_questa.c @@ -0,0 +1,981 @@ +//---------------------------------------------------------------------- +// Copyright 2009-2018 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 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. +//---------------------------------------------------------------------- + +#include "uvm_dpi.h" + + +/* + * UVM HDL access C code. + * + */ + +/* + * This C code checks to see if there is PLI handle + * with a value set to define the maximum bit width. + * + * If no such variable is found, then the default + * width of 1024 is used. + * + * This function should only get called once or twice, + * its return value is cached in the caller. + * + */ +static int uvm_hdl_max_width() +{ + vpiHandle ms; + s_vpi_value value_s = { vpiIntVal, { 0 } }; + ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0); + if(ms == 0) + return 1024; /* If nothing else is defined, + this is the DEFAULT */ + vpi_get_value(ms, &value_s); + return value_s.value.integer; +} + + +// Required to give VHDL back-door access via the FLI +#include +#define MTI_RELEASE_SIGNAL ((mtiForceTypeT)(-1)) + +/* + * FUNCTION -- NODOCS -- uvm_is_vhdl_path + * + * Given a string path, use the FLI to find the named signal. + * Strip off any bit select applied to a vector + * + */ +int uvm_is_vhdl_path(char *path) { + + char *path_ptr = path; + int path_len, idx; + + mtiSignalIdT signal_id; + + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); +// vpi_printf("in uvm_is_vhdl_path with path=%s path_len = %d", path, path_len); + if (*path_ptr != ']') { + signal_id = mti_FindSignal(path); + } else { + while(path_ptr != path && *path_ptr != '[') { + path_ptr--; + path_len--; + } + if(path == path_ptr) { +// vpi_printf("Something strange\n"); + return 0; // Something strange about string + } + if(*path_ptr == '[') { + path_len--; + } + char path_copy[1024]; + strncpy(path_copy, path, path_len); + path_copy[path_len]='\0'; +// vpi_printf("Normalised path is %s path_len = %d", path_copy, path_len); + signal_id = mti_FindSignal(path_copy); +// vpi_printf("returned from MTI land\n"); + } + if (signal_id) { +// vpi_printf("Returning OK\n"); + return 1; + } else { +// vpi_printf("VHDL signal not found\n"); + return 0; + } +} + + + + + + +/* + * FUNCTION -- NODOCS -- string_to_vecval + * + * Given a string, and the number of bits, + * set the Verilog aval/bval in 'value'. + * + * The string will contain 'nbits' characters, either + * '0', '1', 'x' or 'z'. + * + */ +void +string_to_vecval(char *s, int nbits, p_vpi_vecval value) +{ + char *p; + int i, j, k; + int bits_assigned; + int chunks; + int abit, bbit; + char c; + + p = s; + chunks = (nbits-1)/32 + 1; + bits_assigned = 0; + + for(j=0;j= nbits) + break; + } + } +} + +/* + * FUNCTION -- NODOCS -- vecval_to_string + * + * Given a vecval (logic verilog type), return + * a string representation. The returned + * string will contain 'nbits' characters, either + * '0', '1', 'x' or 'z'. + * + * For example: + * vecval_to_string(8, 8'b0000_0001) + * vecval_to_string(8, 8'b0000_00x1) + * + * returns: + * "00000001" + * "000000x1" + */ +char * +vecval_to_string(int nbits, p_vpi_vecval value) +{ + static char *string_buffer = 0; + static int string_buffer_size = 16; + + char *p; + int i, j, k; + int bits_assigned; + int chunks; + int abit, bbit; + char c; + + /* First time, or nbits is really big. */ + if ((string_buffer == 0) || + (nbits > string_buffer_size-1)) { + /* nbits is really big. Make it even + * bigger - to avoid coming in here too many times. + */ + if (nbits > string_buffer_size-1) + string_buffer_size = nbits * 2; + string_buffer = (char *)malloc(string_buffer_size); + } + + p = string_buffer + nbits; + *p = 0; + + chunks = (nbits-1)/32 + 1; + bits_assigned = 0; + + for(j=0;j>k) & 0x01; + bbit = (value[j].bval>>k) & 0x01; + + if ((abit == 1) && (bbit == 0)) c = '1'; + else if ((abit == 0) && (bbit == 0)) c = '0'; + else if ((abit == 1) && (bbit == 1)) c = 'x'; + else if ((abit == 0) && (bbit == 1)) c = 'z'; + + p--; + *p = c; + if (++bits_assigned >= nbits) + break; + } + } + return string_buffer; +} + +/* + * FUNCTION -- NODOCS -- string2vhdl_array_of_int + * + * Given a string of '0', '1', 'x', 'z', convert + * that to a VHDL array of ints. + */ +void +string2vhdl_array_of_int(mtiInt32T *array, + unsigned int elements, char *s) +{ + unsigned int i; + char c; + + if (strlen(s) != elements) { + vpi_printf((PLI_BYTE8*)"FLI: Error: string2vhdl_array_of_int\n"); + vpi_printf((PLI_BYTE8*)"FLI: Length of values %0d does\n", + strlen(s)); + vpi_printf( + (PLI_BYTE8*)"FLI: NOT match the number of elements (%d)\n", + elements); + tf_dofinish(); + } + + for(i = 0; i < elements; i++) { + c = *s++; + if (c == '0') array[i] = 2; + else if (c == '1') array[i] = 3; + else if (c == 'x') array[i] = 1; + else if (c == 'z') array[i] = 4; + } +} + +/* + * FUNCTION -- NODOCS -- string2vhdl_array_of_char + * + * Given a string of '0', '1', 'x', 'z', convert + * that to a VHDL array of ints. + */ +void +string2vhdl_array_of_char(char *array, unsigned int elements, char *s) +{ + unsigned int i; + char c; + + if (strlen(s) != elements) { + vpi_printf((PLI_BYTE8*)"FLI: Error: string2vhdl_array_of_char\n"); + tf_dofinish(); + } + + for(i = 0; i < elements; i++) { + c = *s++; + if (c == '0') array[i] = 2; + else if (c == '1') array[i] = 3; + else if (c == 'x') array[i] = 1; + else if (c == 'z') array[i] = 4; + } +} + + +/* + * FUNCTION -- NODOCS -- vhdl_array_of_char2string + * + * Given an array of VHDL values, convert them + * to a string of '0', '1', 'x' or 'z'. + */ +char * +vhdl_array_of_char2string(char *array, int elements) +{ + int i; + char *s; + char *p; + char c; + + s = (char *)malloc(elements+1); + p = s; + for(i = 0; i < elements; i++) { + if (array[i] == 2) c = '0'; + else if (array[i] == 3) c = '1'; + else if (array[i] == 1) c = 'x'; + else if (array[i] == 4) c = 'z'; + else c = '-'; + *p++ = c; + } + *p = 0; + return s; +} + +/* + * FUNCTION -- NODOCS -- vhdl_array_of_int2string + * + * Given an array of VHDL values, convert them + * to a string of '0', '1', 'x' or 'z'. + */ +char * +vhdl_array_of_int2string(int *array, int elements) +{ + int i; + char *s; + char *p; + char c; + + s = (char *)malloc(elements+1); + p = s; + for(i = 0; i < elements; i++) { + if (array[i] == 2) c = '0'; + else if (array[i] == 3) c = '1'; + else if (array[i] == 1) c = 'x'; + else if (array[i] == 4) c = 'z'; + else c = '-'; + *p++ = c; + } + *p = 0; + return s; +} + + +/* + * FUNCTION -- NODOCS -- uvm_register_get_vhdl + * + * Used to get the value of a VHDL signal, and return + * the value as a Verilog aval/bval pair. + */ + +int uvm_register_get_vhdl(char *path, p_vpi_vecval value) +{ + mtiSignalIdT signal_id; + mtiTypeIdT signal_type; + mtiInt32T *int_array; + char *char_array; + int nbits; + + char *path_ptr = path; + int path_len; + + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + if(*path_ptr != ']') { + // Not a vectored access + signal_id = mti_FindSignal(path); + if (signal_id) { + char_array = (char*)mti_GetArraySignalValue(signal_id, 0); + signal_type = mti_GetSignalType(signal_id); + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) { + nbits = mti_TickLength(signal_type); + } else { + nbits = 1; // Has to be a scalar signal + } + string_to_vecval( + vhdl_array_of_char2string(char_array, nbits), + nbits, + value); + mti_VsimFree(char_array); + return 1; + } else { + vpi_printf( + (PLI_BYTE8*)"FLI: uvm_register_get_vhdl() failed. Cannot find signal '%s'\n", + path); + return 0; + } + } else { + // A vectored access +// vpi_printf("Read access to a VHDL vector"); + while(path_ptr != path && *path_ptr != '[') { + path_ptr--; + path_len--; + } + // Extract the range from the path + int lhs, rhs, width, incr; + + path_len--; + char path_copy[1024]; + strncpy(path_copy, path, path_len); + path_copy[path_len]='\0'; + + // Find out no of bits in vector + signal_id = mti_FindSignal(path_copy); + if (signal_id) { + char_array = (char*)mti_GetArraySignalValue(signal_id, 0); + signal_type = mti_GetSignalType(signal_id); + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) { + nbits = mti_TickLength(signal_type); + } else { + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ENUM) { + nbits = 1; + } + } + if(strchr(path_ptr, ':') != NULL) { + + if(sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) { + int i; + char index_str[20]; + // char path_str[80]; + // char vector_val[128]; + // char *bit_val[5]; + // char* fred; + + incr = (lhs>rhs) ? 1 : -1; + width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1; + char* vectors = vhdl_array_of_char2string(char_array, nbits); +// vpi_printf("Vector found was %s [%d:%d] incr is %d nbits is %d\n", vectors, lhs, rhs, incr, nbits); + char reduced_vector[256]; + for (i = 0; i < width; i++) { + reduced_vector[i] = vectors[(nbits-1)-lhs]; + lhs -= incr; + } +// vpi_printf("Vector[%d:%d] is %s", lhs, rhs, reduced_vector); + string_to_vecval(reduced_vector, width, value); + } else { + return 0; + } + } else { + if(sscanf(path_ptr, "[%u]", &rhs)) { + char* vectors = vhdl_array_of_char2string(char_array, nbits); + char reduced_vector[256]; + reduced_vector[0] = vectors[(nbits-1)-rhs]; + string_to_vecval(reduced_vector, 1, value); + } else { + return 0; + } + } + + + // string_to_vecval( + // vhdl_array_of_char2string(char_array, nbits), + // nbits, + // value); + + + mti_VsimFree(char_array); + return 1; + + } else { +// vpi_printf("VHDL signal not for %s", path_copy); + return 0; + } + + + } +} + +/* + * FUNCTION -- NODOCS -- uvm_register_set_vhdl + * + * Used to set the value of a VHDL signal, given + * the value as a Verilog aval/bval pair. + */ +int uvm_register_set_vhdl(char *path, p_vpi_vecval value, mtiForceTypeT forceType) +{ + mtiSignalIdT signal_id; + mtiTypeIdT signal_type, element_type; + mtiInt32T *int_array; + char *char_array; + char *path_ptr = path; + int path_len; + + int nbits; + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + vpi_printf((PLI_BYTE8*)"Setting vhdl path %s\n", path); + + if(*path_ptr != ']') { + // Not a vectored access + signal_id = mti_FindSignal(path); + if (signal_id) { + char_array = (char*)mti_GetArraySignalValue(signal_id, 0); + signal_type = mti_GetSignalType(signal_id); + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) { + nbits = mti_TickLength(signal_type); + } else { + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ENUM) { + nbits = 1; + } + } + if (forceType == MTI_RELEASE_SIGNAL) { + mti_ReleaseSignal(signal_id); + } else { + mti_ForceSignal(signal_id, vecval_to_string(nbits, value), 0, forceType, -1, -1); + } + mti_VsimFree(char_array); + return 1; + } else { + vpi_printf( + (PLI_BYTE8*)"FLI: uvm_register_set_vhdl() failed. Cannot find signal '%s'\n", + path); + return 0; + } + } else { + // A vectored access: + while(path_ptr != path && *path_ptr != '[') { + path_ptr--; + path_len--; + } + // Extract the range from the path + int lhs, rhs, width, incr; + + path_len--; + char path_copy[1024]; + strncpy(path_copy, path, path_len); + path_copy[path_len]='\0'; + + // Find out no of bits in vector + signal_id = mti_FindSignal(path_copy); + if (signal_id) { + char_array = (char*)mti_GetArraySignalValue(signal_id, 0); + signal_type = mti_GetSignalType(signal_id); + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ARRAY) { + nbits = mti_TickLength(signal_type); + } else { + if(mti_GetTypeKind(signal_type) == MTI_TYPE_ENUM) { + nbits = 1; + } + } + } + + if(strchr(path_ptr, ':') != NULL) { + if(sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) { + int i; + char index_str[20]; + char path_str[80]; + char vector_val[128]; + + strcpy(vector_val,vecval_to_string(nbits, value)); +// vpi_printf("LHS %u RHS %u", lhs, rhs); +// vpi_printf("Vector string is %s", vector_val); + incr = (lhs>rhs) ? 1 : -1; + width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1; + + for (i = 0; i < width; i++) { + sprintf(index_str,"(%u)",rhs); + rhs += incr; + strcpy(path_str, path_copy); +// vpi_printf("Index string is %s\n", index_str); + strcat(path_str,index_str); + signal_id = mti_FindSignal(path_str); + if (forceType == MTI_RELEASE_SIGNAL) { + mti_ReleaseSignal(signal_id); + } else { + if(vector_val[(nbits-i)-1] == '1') { +// vpi_printf("Path string is %s = 1\n", path_str); + mti_ForceSignal(signal_id, (char*)"1", 0, MTI_FORCE_DEPOSIT, -1, -1); + } else { +// vpi_printf("Path string is %s = 0\n", path_str); + mti_ForceSignal(signal_id, (char*)"0", 0, MTI_FORCE_DEPOSIT, -1, -1); + } + } + } + } + } else { + vpi_printf((PLI_BYTE8*)"Single vector\n"); + if(sscanf(path_ptr,"[%u]", &rhs)) { + char index_str[20]; + char path_str[80]; + char vector_val[128]; + + strcpy(vector_val,vecval_to_string(nbits, value)); +// vpi_printf("Vector string is %s", vector_val); + sprintf(index_str,"(%u)",rhs); + strcpy(path_str, path_copy); +// vpi_printf("Index string is %s\n", index_str); + strcat(path_str,index_str); + signal_id = mti_FindSignal(path_str); + if (forceType == MTI_RELEASE_SIGNAL) { + mti_ReleaseSignal(signal_id); + } else { + if(vector_val[(nbits-1)-rhs] == '1') { +// vpi_printf("Path string is %s = 1\n", path_str); + mti_ForceSignal(signal_id, (char*)"1", 0, MTI_FORCE_DEPOSIT, -1, -1); + } else { +// vpi_printf("Path string is %s = 0\n", path_str); + mti_ForceSignal(signal_id, (char*)"0", 0, MTI_FORCE_DEPOSIT, -1, -1); + } + } + } + + + } + +// vpi_printf("Finished setting VHDL"); + mti_VsimFree(char_array); + return 1; + } + +} + +// + +static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag); +static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag); +static int partsel = 0; + +/* + * Given a path with part-select, break into individual bit accesses + * path = pointer to user string + * value = pointer to logic vector + * flag = deposit vs force/release options, etc + */ +static int uvm_hdl_set_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + char *path_ptr = path; + int path_len, idx; + svLogicVecVal bit_value; + + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + if (*path_ptr != ']') + return 0; + + while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != ':') + return 0; + + while(path_ptr != path && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != '[') + return 0; + + int lhs, rhs, width, incr; + + // extract range from path + if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) { + char index_str[20]; + int i; + path_ptr++; + path_len = (path_len - (path_ptr - path)); + incr = (lhs>rhs) ? 1 : -1; + width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1; + vpi_printf((PLI_BYTE8*)"LHS %u RHS %u\n", lhs, rhs); + + // perform set for each individual bit + for (i=0; i < width; i++) { + sprintf(index_str,"%u]",rhs); + strncpy(path_ptr,index_str,path_len); + svGetPartselLogic(&bit_value,value,i,1); + rhs += incr; + if (!uvm_hdl_set_vlog(path,&bit_value,flag)) + return 0; + } + return 1; + } +} + + +/* + * Given a path with part-select, break into individual bit accesses + * path = pointer to user string + * value = pointer to logic vector + * flag = deposit vs force/release options, etc + */ +static int uvm_hdl_get_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + char *path_ptr = path; + int path_len, idx; + svLogicVecVal bit_value; + + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + if (*path_ptr != ']') + return 0; + + while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != ':') + return 0; + + while(path_ptr != path && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != '[') + return 0; + + int lhs, rhs, width, incr; + + // extract range from path + if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) { + char index_str[20]; + int i; + path_ptr++; + path_len = (path_len - (path_ptr - path)); + incr = (lhs>rhs) ? 1 : -1; + width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1; + bit_value.aval = 0; + bit_value.bval = 0; + partsel = 1; + for (i=0; i < width; i++) { + int result; + svLogic logic_bit; + sprintf(index_str,"%u]",rhs); + strncpy(path_ptr,index_str,path_len); + result = uvm_hdl_get_vlog(path,&bit_value,flag); + logic_bit = svGetBitselLogic(&bit_value,0); + svPutPartselLogic(value,bit_value,i,1); + rhs += incr; + if (!result) + return 0; + } + partsel = 0; + return 1; + } +} + + +/* + * Given a path, look the path name up using the PLI, + * and set it to 'value'. + */ +static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + static int maxsize = -1; + vpiHandle r; + s_vpi_value value_s = { vpiIntVal, { 0 } }; + s_vpi_time time_s = { vpiSimTime, 0, 0, 0.0 }; + + //vpi_printf("uvm_hdl_set_vlog(%s,%0x)\n",path,value[0].aval); + + int result = 0; + result = uvm_hdl_set_vlog_partsel(path,value,flag); +// vpi_printf("Verilog path set %sx result is %0d\n", path, result); + if (result < 0) + return 0; + if (result == 1) + return 1; + + if (!strncmp(path,"$root.",6)) + r = vpi_handle_by_name(path+6, 0); + else + r = vpi_handle_by_name(path, 0); + + if(r == 0) + { + const char * err_str = "set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name"; + char buffer[strlen(err_str) + strlen(path)]; + sprintf(buffer, err_str, path); + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 0; + } + else + { + if(maxsize == -1) + maxsize = uvm_hdl_max_width(); + + if (flag == vpiReleaseFlag) { + //size = vpi_get(vpiSize, r); + //value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval))); + //value = &value_p; + } + value_s.format = vpiVectorVal; + value_s.value.vector = value; + vpi_put_value(r, &value_s, &time_s, flag); + //if (value_p != NULL) + // free(value_p); + if (value == NULL) { + value = value_s.value.vector; + } + } + vpi_release_handle(r); + return 1; +} + + +/* + * Given a path, look the path name up using the PLI + * and return its 'value'. + */ +static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + static int maxsize = -1; + int i, size, chunks; + vpiHandle r; + s_vpi_value value_s; + + if (!partsel) { + maxsize = uvm_hdl_max_width(); + chunks = (maxsize-1)/32 + 1; + for(i=0;i maxsize) + { + const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH="; + char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))]; + sprintf(buffer, err_str, path, size, maxsize); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + //tf_dofinish(); + vpi_release_handle(r); + return 0; + } + chunks = (size-1)/32 + 1; + + value_s.format = vpiVectorVal; + vpi_get_value(r, &value_s); + /*dpi and vpi are reversed*/ + for(i=0;i 0) + result = uvm_register_get_vhdl(path, value); + } else { + result = uvm_hdl_set_vlog(path, value, vpiReleaseFlag); + if (result > 0) + result = uvm_hdl_get_vlog(path, value, vpiNoDelay); + } + return result; +} + +/* + * Given a path, look the path name up using the PLI + * or the FLI, and release it. + */ +int uvm_hdl_release(char *path) +{ + s_vpi_vecval value; + p_vpi_vecval valuep = &value; + if(uvm_is_vhdl_path(path)) { + return uvm_register_set_vhdl(path, valuep, MTI_RELEASE_SIGNAL); + } else { + return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag); + } +} + diff --git a/test_regress/t/t_uvm/dpi/uvm_hdl_vcs.c b/test_regress/t/t_uvm/dpi/uvm_hdl_vcs.c new file mode 100644 index 0000000000..1719d125d7 --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_hdl_vcs.c @@ -0,0 +1,1198 @@ +//---------------------------------------------------------------------- +// Copyright 2009-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 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. +//---------------------------------------------------------------------- + +#include "uvm_dpi.h" +#include + +#include "svdpi.h" +#include "vcsuser.h" +#include "sv_vpi_user.h" + +#ifdef VCSMX +#include "mhpi_user.h" +#include "vhpi_user.h" +#endif + +#if defined(VCSMX_FAST_UVM) && !defined(MHPI_FAST_UVM) +#error “UVM_ERROR: THIS VERSION OF VCS DOESN’T SUPPORT VCSMX_FAST_UVM. Compile without -DVCSMX_FAST_UVM” +#endif + +/* + * Functionn to check if target variable is compatible with vector + */ +/* + * This code ceccks if the given handle is not of type Array or unpacked + * struct + */ + +static int vector_compat_type(vpiHandle obj) +{ + int vector_compatible = 1; + switch(vpi_get(vpiType, obj)) { + case vpiArrayVar: + case vpiArrayNet: + vector_compatible = 0; + break; + case vpiStructVar: + case vpiUnionVar: + if (vpi_get(vpiVector, obj) == 0) { + vector_compatible = 0; + } + break; + } + if (!vector_compatible) { + return 0; + } + return 1; +} + +static int vector_compat_type_stub(vpiHandle obj) +{ + return 1; +} + +#ifdef UVM_DPI_DISABLE_DO_TYPE_CHECK +#undef UVM_DPI_DO_TYPE_CHECK +#endif + +#ifdef UVM_DPI_DO_TYPE_CHECK + static int (*check_type)(vpiHandle) = &vector_compat_type; +#else + static int (*check_type)(vpiHandle) = &vector_compat_type_stub; +#endif + +/* + * UVM HDL access C code. + * + */ + +static char* get_memory_for_alloc(int need) +{ + static int alloc_size = 0; + static char* alloc = NULL; + if (need > alloc_size) { + if (alloc_size == 0) alloc_size = need; + while (alloc_size < need) alloc_size *= 2; + alloc = (char*)realloc(alloc, alloc_size); + } + return alloc; +} +/* + * This C code checks to see if there is PLI handle + * with a value set to define the maximum bit width. + * + * If no such variable is found, then the default + * width of 1024 is used. + * + * This function should only get called once or twice, + * its return value is cached in the caller. + * + */ +static int uvm_hdl_max_width() +{ + vpiHandle ms; + s_vpi_value value_s = { vpiIntVal, { 0 } }; + ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0); + if(ms == 0) + return 1024; /* If nothing else is defined, + this is the DEFAULT */ + vpi_get_value(ms, &value_s); + return value_s.value.integer; +} + + +/* + * Given a path, look the path name up using the PLI, + * and set it to 'value'. + */ +#ifdef VCSMX_FAST_UVM +static int uvm_hdl_set_vlog(vpiHandle r, char* path, p_vpi_vecval value, PLI_INT32 flag) +{ + static int maxsize = -1; + s_vpi_value value_s = { vpiIntVal, { 0 } }; + s_vpi_time time_s = { vpiSimTime, 0, 0, 0.0 }; + + if(r == 0) + { + const char * err_str = "set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name"; + char buffer[strlen(err_str) + strlen(path)]; + sprintf(buffer, err_str, path); + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + + __LINE__); + return 0; + } + else + { + if(maxsize == -1) + maxsize = uvm_hdl_max_width(); + + if (flag == vpiReleaseFlag) { + //size = vpi_get(vpiSize, r); + //value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval))); + //value = &value_p; + } + value_s.format = vpiVectorVal; + value_s.value.vector = value; + if (!check_type(r)) { + vpi_printf((PLI_BYTE8*) "UVM_ERROR: Object pointed to by path '%s' is not of supported type\n" \ + "(Unpacked Array/Struct/Union type) for reading/writing value.", path); + return 0; + } + vpi_put_value(r, &value_s, &time_s, flag); + //if (value_p != NULL) + // free(value_p); + if (value == NULL) { + value = value_s.value.vector; + } + } + return 1; +} +#else +static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + static int maxsize = -1; + vpiHandle r; + s_vpi_value value_s = { vpiIntVal, { 0 } }; + s_vpi_time time_s = { vpiSimTime, 0, 0, 0.0 }; + +#ifdef VCSMX +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif + mhpiHandleT h = mhpi_handle_by_name(path, 0); + r = (vpiHandle) mhpi_get_vpi_handle(h); +#else + r = vpi_handle_by_name(path, 0); +#endif + + if(r == 0) + { + const char * err_str = "set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name"; + char buffer[strlen(err_str) + strlen(path)]; + sprintf(buffer, err_str, path); + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + + __LINE__); + return 0; + } + else + { + if(maxsize == -1) + maxsize = uvm_hdl_max_width(); + + if (flag == vpiReleaseFlag) { + //size = vpi_get(vpiSize, r); + //value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval))); + //value = &value_p; + } + value_s.format = vpiVectorVal; + value_s.value.vector = value; + if (!check_type(r)) { + vpi_printf((PLI_BYTE8*) "UVM_ERROR: Object pointed to by path '%s' is not of supported type\n" \ + "(Unpacked Array/Struct/Union type) for reading/writing value.", path); + return 0; + } + vpi_put_value(r, &value_s, &time_s, flag); + //if (value_p != NULL) + // free(value_p); + if (value == NULL) { + value = value_s.value.vector; + } + } + return 1; +} +#endif + + +/* + * Given a path, look the path name up using the PLI + * and return its 'value'. + */ +#ifdef VCSMX_FAST_UVM +static int uvm_hdl_get_vlog(vpiHandle r, char* path, p_vpi_vecval value, PLI_INT32 flag) +{ + static int maxsize = -1; + int i, size, chunks; + s_vpi_value value_s; + + + if(r == 0) + { + const char * err_str = "get: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name"; + char buffer[strlen(err_str) + strlen(path)]; + sprintf(buffer, err_str, path); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/HDL_GET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + // Exiting is too harsh. Just return instead. + // tf_dofinish(); + return 0; + } + else + { + if(maxsize == -1) + maxsize = uvm_hdl_max_width(); + + size = vpi_get(vpiSize, r); + if(size > maxsize) + { + const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH="; + char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))]; + sprintf(buffer, err_str, path, size, maxsize); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 0; + } + chunks = (size-1)/32 + 1; + + value_s.format = vpiVectorVal; + if (!check_type(r)) { + vpi_printf((PLI_BYTE8*) "UVM_ERROR: Object pointed to by path '%s' is not of supported type\n" \ + "(Unpacked Array/Struct/Union type) for reading/writing value.", path); + return 0; + } + vpi_get_value(r, &value_s); + /*dpi and vpi are reversed*/ + for(i=0;i maxsize) + { + const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH="; + char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))]; + sprintf(buffer, err_str, path, size, maxsize); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 0; + } + chunks = (size-1)/32 + 1; + + value_s.format = vpiVectorVal; + if (!check_type(r)) { + vpi_printf((PLI_BYTE8*) "UVM_ERROR: Object pointed to by path '%s' is not of supported type\n" \ + "(Unpacked Array/Struct/Union type) for reading/writing value.", path); + return 0; + } + vpi_get_value(r, &value_s); + /*dpi and vpi are reversed*/ + for(i=0;i maxsize) { + const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH="; + char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))]; + sprintf(buffer, err_str, path, size, maxsize); + m_uvm_report_dpi(M_UVM_ERROR, (char*)"UVM/DPI/VHDL_GET", &buffer[0], M_UVM_NONE, (char*)__FILE__, __LINE__); + return 0; + } + + // start to convert to p_vpi_vecval + memset(value, 0, (maxsize-1)/32+1); + vhpiHandleT baseTypeH = vhpi_handle (vhpiBaseType, r); + char *typeName = vhpi_get_str (vhpiNameP, baseTypeH); + if ((vhpi_get(vhpiIsScalarP, r)) == 1) { + if (!strcmp(typeName, "INTEGER")) { + value_s.format = vhpiIntVal; + rtn = vhpi_get_value(r, &value_s); + value[0].aval = value_s.value.intg; + value[0].bval = 0; + return 1; + } + } + chunks = (size - 1)/ 32 + 1; + value_s.format = vhpiEnumVecVal; + value_s.bufSize = size; + value_s.value.str = get_memory_for_alloc(size); + rtn = vhpi_get_value(r, &value_s); + if (rtn > 0) { + value_s.value.str = get_memory_for_alloc(rtn); + value_s.bufSize = rtn; + vhpi_get_value(r, &value_s); + } + + // start to convert to p_vpi_vecval + memset(value, 0, (maxsize-1)/32+1); + bit = 0; + for (i = 0; i < chunks && bit < size; ++i) { + aval = 0; + bval = 0; + for(j=0;(j<32) && (bit= 0 ; i--) { + tmp[0] = binVal[i]; + bin = atoi(tmp); + dec = dec+(bin*(pow(2,j))); + j++; + } + return(dec); +} + + +/* + *decimal to hex conversion + */ +char *uvm_hdl_dtob(unsigned long int decimalNumber, unsigned long int msb) { + unsigned int remainder, quotient; + int i=0,j, length; + int binN[65]; + static char binaryNumber[65]; + char *str = (char*) malloc(sizeof(char)); + memset(binN, 0, 65*sizeof(int)); + + quotient = decimalNumber; + + + do { + binN[i++] = quotient%2; + quotient = quotient/2; + } while (quotient!=0); + if (!msb) + length = 32; + else + length = i; + + for (i=length-1, j = 0; i>=0; i--) { + binaryNumber[j++] = binN[i]?'1':'0'; + } + binaryNumber[j] = '\0'; + return(binaryNumber); +} + + +/* + * Mixed lanaguage API Get calls + */ +#ifdef VCSMX +#ifdef VCSMX_FAST_UVM +int uvm_hdl_get_mhdl(vhpiHandleT vhpiH, char *path, p_vpi_vecval value) { + + long int value_int; + static int maxsize = -1; + + + char *binVal; + int i = 0; + vhpiValueT value1; + p_vpi_vecval vecval; + int size = 0; +/* +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif + mhpiHandleT mhpiH = mhpi_uvm_handle_by_name(path, 0); + vhpiHandleT vhpiH = (long unsigned int *)mhpi_get_vhpi_handle(mhpiH);*/ + value1.format=vhpiStrVal; + size = vhpi_get(vhpiSizeP, vhpiH); + + if (maxsize == -1) + maxsize = uvm_hdl_max_width(); + + if(size > maxsize) + { + const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH="; + char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))]; + sprintf(buffer, err_str, path, size, maxsize); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 0; + } + + value1.bufSize = size+1; + value1.value.str = get_memory_for_alloc(size + 1); + if (vhpi_get_value(vhpiH, &value1) == 0) { + int max_i = (size -1)/32 + 1; + char sub_value[33]; + binVal = value1.value.str; + for (int i = 0; i < max_i; i++) { + int bits_to_consider = 32; + + if (i == 0) { + bits_to_consider = size - (max_i-1)*32; + } + + strncpy(sub_value, binVal, bits_to_consider); + sub_value[bits_to_consider]= '\0'; + + for (int j = 0; j < bits_to_consider; j++) { + switch(sub_value[j]) { + case '0': + value[max_i-i-1].aval = value[max_i-i-1].aval << 1; + value[max_i-i-1].bval = value[max_i-i-1].bval << 1; + break; + case '1': + value[max_i-i-1].aval = (value[max_i-i-1].aval << 1) + 1; + value[max_i-i-1].bval = value[max_i-i-1].bval << 1; + break; + case 'U': + case 'X': + value[max_i-i-1].aval = (value[max_i-i-1].aval << 1) + 1; + value[max_i-i-1].bval = (value[max_i-i-1].bval << 1) + 1; + break; + case 'Z': + value[max_i-i-1].aval = value[max_i-i-1].aval << 1; + value[max_i-i-1].bval = (value[max_i-i-1].bval << 1) + 1; + break; + default: + value[max_i-i-1].aval = (value[max_i-i-1].aval << 1) + 1; + value[max_i-i-1].bval = (value[max_i-i-1].bval << 1) + 1; + } + } + binVal = binVal+32; + } + + return(1); + + + } else { + return (0); + } + +} +#else +int uvm_hdl_get_mhdl(char *path, p_vpi_vecval value) { + + long int value_int; + static int maxsize = -1; + + + char *binVal; + int i = 0; + vhpiValueT value1; + p_vpi_vecval vecval; + int size = 0; + +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif + mhpiHandleT mhpiH = mhpi_handle_by_name(path, 0); + vhpiHandleT vhpiH = (long unsigned int *)mhpi_get_vhpi_handle(mhpiH); + value1.format=vhpiStrVal; + size = vhpi_get(vhpiSizeP, vhpiH); + + if (maxsize == -1) + maxsize = uvm_hdl_max_width(); + + if(size > maxsize) + { + const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH="; + char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))]; + sprintf(buffer, err_str, path, size, maxsize); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/HDL_SET", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 0; + } + + //value1.bufSize = (size)/8 + 1; + value1.bufSize = size+1; + value1.value.str = (char*)malloc(value1.bufSize*sizeof(char)); + + if (vhpi_get_value(vhpiH, &value1) == 0) { + int max_i = (size -1)/32 + 1; + char sub_value[33]; + binVal = value1.value.str; + for (int i = 0; i < max_i; i++) { + int bits_to_consider = 32; + + if (i == 0) { + bits_to_consider = size - (max_i-1)*32; + } + + strncpy(sub_value, binVal, bits_to_consider); + sub_value[bits_to_consider]= '\0'; + + for (int j = 0; j < bits_to_consider; j++) { + switch(sub_value[j]) { + case '0': + value[max_i-i-1].aval = value[max_i-i-1].aval << 1; + value[max_i-i-1].bval = value[max_i-i-1].bval << 1; + break; + case '1': + value[max_i-i-1].aval = (value[max_i-i-1].aval << 1) + 1; + value[max_i-i-1].bval = value[max_i-i-1].bval << 1; + break; + case 'U': + case 'X': + value[max_i-i-1].aval = (value[max_i-i-1].aval << 1) + 1; + value[max_i-i-1].bval = (value[max_i-i-1].bval << 1) + 1; + break; + case 'Z': + value[max_i-i-1].aval = value[max_i-i-1].aval << 1; + value[max_i-i-1].bval = (value[max_i-i-1].bval << 1) + 1; + break; + default: + value[max_i-i-1].aval = (value[max_i-i-1].aval << 1) + 1; + value[max_i-i-1].bval = (value[max_i-i-1].bval << 1) + 1; + } + } + binVal = binVal+32; + } + mhpi_release_parent_handle(mhpiH); + + free(value1.value.str); + return(1); + + + } else { + mhpi_release_parent_handle(mhpiH); + free(value1.value.str); + return (0); + } + +} +#endif +#endif + +#ifdef VCSMX_FAST_UVM +char* uvm_hdl_read_string(char* path) +{ +#ifdef VCSMX +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif + mhpiHandleT mhpiH = mhpi_uvm_handle_by_name(path, 0); + if (mhpi_get(mhpiPliP, mhpiH) == mhpiVhpiPli) { + vhpiValueT getValue; + char* valueStr = (char*)0; + vhpiIntT strValueSize = 0; + vhpiHandleT h = (vhpiHandleT)mhpi_get_vhpi_handle(mhpiH); + mhpi_release_parent_handle(mhpiH); + if (h) { + strValueSize = vhpi_value_size(h, vhpiStrVal); + if (strValueSize) { + getValue.value.str = get_memory_for_alloc( 8*strValueSize+1); + } else { + return valueStr; + } + + getValue.format = vhpiStrVal; + getValue.bufSize = strValueSize; + if (!vhpi_get_value(h, &getValue)) { + valueStr = getValue.value.str; + getValue.value.str = (char*)0; + } + vhpi_release_handle(h); + } + return valueStr; + } else if (mhpi_get(mhpiPliP, mhpiH) == mhpiVpiPli){ + vpiHandle h = (vpiHandle)mhpi_get_vpi_handle(mhpiH); + mhpi_release_parent_handle(mhpiH); + + if (h) { + s_vpi_value getValue; + getValue.format = vpiStringVal; + if (!check_type(h)) { + vpi_printf((PLI_BYTE8*) "UVM_ERROR: Object pointed to by path '%s' is not of supported type\n" \ + "(Unpacked Array/Struct/Union type) for reading/writing value.", path); + return 0; + } + vpi_get_value(h, &getValue); + vpi_release_handle(h); + return getValue.value.str; + } + return (char*)0; + } +#else + vpiHandle h = vpi_handle_by_name(path, 0); + if (h) { + s_vpi_value getValue; + getValue.format = vpiStringVal; + if (!check_type(h)) { + vpi_printf((PLI_BYTE8*) "UVM_ERROR: Object pointed to by path '%s' is not of supported type\n" \ + "(Unpacked Array/Struct/Union type) for reading/writing value.", path); + return 0; + } + vpi_get_value(h, &getValue); + vpi_release_handle(h); + return getValue.value.str; + } + return (char*)0; +#endif +} +#else +char* uvm_hdl_read_string(char* path) +{ + vpi_printf((PLI_BYTE8*) "UVM_ERROR: uvm_hdl_read_string is not supported, please compile with -DVCSMX_FAST_UVM\n"); + return (char*)0; +} +#endif +/* + * Given a path, look the path name up using the PLI + * or the VHPI, and return its 'value'. + */ + +int uvm_hdl_read(char *path, p_vpi_vecval value) +{ +#ifndef VCSMX +#ifdef VCSMX_FAST_UVM + r = vpi_handle_by_name(path, 0); + int res = uvm_hdl_get_vlog(r, path, value, vpiNoDelay); + vpi_release_handle(r); + return res; +#else + return uvm_hdl_get_vlog(path, value, vpiNoDelay); +#endif +#else +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif +#ifdef VCSMX_FAST_UVM + mhpiHandleT h = mhpi_uvm_handle_by_name(path, 0); + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + vpiHandle r = (vpiHandle) mhpi_get_vpi_handle(h); + int res = uvm_hdl_get_vlog(r, path, value, vpiNoDelay); + mhpi_release_handle(h); + return res; + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + vhpiHandleT r = (vhpiHandleT) mhpi_get_vhpi_handle(h); + //return uvm_hdl_get_mhdl(r, path,value); + int res = uvm_hdl_get_vhpi(r, path, value); + mhpi_release_handle(h); + return res; + } +#else + mhpiHandleT h = mhpi_handle_by_name(path, 0); + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + mhpi_release_parent_handle(h); + return uvm_hdl_get_vlog(path, value, vpiNoDelay); + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + + mhpi_release_parent_handle(h); + return uvm_hdl_get_mhdl(path,value); + } +#endif +#endif +} + + +/* + * Mixed Language API Set calls + */ +#ifdef VCSMX +#ifdef VCSMX_FAST_UVM +int uvm_hdl_set_mhdl(mhpiHandleT h, char *path, p_vpi_vecval value, mhpiPutValueFlagsT flags) +{ + mhpiRealT forceDelay = 0; + mhpiRealT cancelDelay = -1; + mhpiReturnT ret; + mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, h); + + PLI_UINT32 size = mhpi_get(mhpiSizeP, h); + PLI_UINT32 max_i = (size-1)/32 + 1; + char* buf = get_memory_for_alloc(size + 1); + buf[0] = '\0'; + + for (int i = max_i -1; i >= 0; i--) { + int sz; + char* force_value =uvm_hdl_dtob(value[i].aval, ((max_i -1) ==i)); + sz = ((max_i - 1) == i) ? size - 32*(max_i-1) : 32; + strncat(buf, force_value, sz); + } + + ret = mhpi_force_value_by_handle(h, buf, flags, forceDelay, cancelDelay); + if (ret == mhpiRetOk) { + return(1); + } + else + return(0); +} +#else +int uvm_hdl_set_mhdl(char *path, p_vpi_vecval value, mhpiPutValueFlagsT flags) +{ +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif + mhpiRealT forceDelay = 0; + mhpiRealT cancelDelay = -1; + mhpiReturnT ret; + mhpiHandleT h = mhpi_handle_by_name(path, 0); + mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, h); + + PLI_UINT32 size = mhpi_get(mhpiSizeP, h); + PLI_UINT32 max_i = (size-1)/32 + 1; + char* buf = (char *) malloc(sizeof(char)*(size+1)); + buf[0] = '\0'; + + for (int i = max_i -1; i >= 0; i--) { + int sz; + char* force_value =uvm_hdl_dtob(value[i].aval, ((max_i -1) ==i)); + sz = ((max_i - 1) == i) ? size - 32*(max_i-1) : 32; + strncat(buf, force_value, sz); + } + + ret = mhpi_force_value(path, mhpi_mhRegion, buf, flags, forceDelay, cancelDelay); + mhpi_release_parent_handle(h); + if (ret == mhpiRetOk) { + return(1); + } + else + return(0); +} +#endif +#endif + +/* + * Given a path, look the path name up using the PLI + * or the VHPI, and set it to 'value'. + */ +int uvm_hdl_deposit(char *path, p_vpi_vecval value) +{ +#ifndef VCSMX +#ifdef VCSMX_FAST_UVM + vpiHandle r = vpi_handle_by_name(path, 0); + int res = uvm_hdl_set_vlog(r, path, value, vpiNoDelay); + vpi_release_handle(r); + return res; +#else + return uvm_hdl_set_vlog(path, value, vpiNoDelay); +#endif +#else +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif +#ifdef VCSMX_FAST_UVM + mhpiHandleT h = mhpi_uvm_handle_by_name(path, 0); + + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + vpiHandle r = (vpiHandle) mhpi_get_vpi_handle(h); + int res = uvm_hdl_set_vlog(r, path, value, vpiNoDelay); + mhpi_release_handle(h); + return res; + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + int res = uvm_hdl_set_mhdl(h, path, value, mhpiNoDelay); + return res; + } + else + return (0); +#else + mhpiHandleT h = mhpi_handle_by_name(path, 0); + + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + mhpi_release_parent_handle(h); + return uvm_hdl_set_vlog(path, value, vpiNoDelay); + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + mhpi_release_parent_handle(h); + return uvm_hdl_set_mhdl(path, value, mhpiNoDelay); + } + else + return (0); +#endif +#endif +} + + +/* + * Given a path, look the path name up using the PLI + * or the VHPI, and set it to 'value'. + */ +int uvm_hdl_force(char *path, p_vpi_vecval value) +{ +#ifndef VCSMX +#ifdef VCSMX_FAST_UVM + vpiHandle r = vpi_handle_by_name(path, 0); + int res = uvm_hdl_set_vlog(r, path, value, vpiForceFlag); + vpi_release_handle(r); + return res; +#else + return uvm_hdl_set_vlog(path, value, vpiForceFlag); +#endif +#else +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif +#ifdef VCSMX_FAST_UVM + mhpiHandleT h = mhpi_uvm_handle_by_name(path, 0); + + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + vpiHandle r = (vpiHandle) mhpi_get_vpi_handle(h); + int res = uvm_hdl_set_vlog(r, path, value, vpiForceFlag); + mhpi_release_handle(h); + return res; + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + int res = uvm_hdl_set_mhdl(h, path, value, mhpiForce); + return res; + } + else + return (0); +#else + mhpiHandleT h = mhpi_handle_by_name(path, 0); + + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + mhpi_release_parent_handle(h); + return uvm_hdl_set_vlog(path, value, vpiForceFlag); + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + + mhpi_release_parent_handle(h); + return uvm_hdl_set_mhdl(path, value, mhpiForce); + + } + else + return (0); +#endif +#endif +} + + +/* + * Given a path, look the path name up using the PLI + * or the VHPI, and release it. + */ +int uvm_hdl_release_and_read(char *path, p_vpi_vecval value) +{ +#ifndef VCSMX +#ifdef VCSMX_FAST_UVM + vpiHandle r = vpi_handle_by_name(path, 0); + int res = uvm_hdl_set_vlog(r, path, value, vpiReleaseFlag); + vpi_release_handle(r); + return res; +#else + return uvm_hdl_set_vlog(path, value, vpiReleaseFlag); +#endif +#else +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif +#ifdef VCSMX_FAST_UVM + mhpiHandleT mhpiH = mhpi_uvm_handle_by_name(path, 0); +#else + mhpiHandleT mhpiH = mhpi_handle_by_name(path, 0); +#endif + mhpiReturnT ret; + mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, mhpiH); + if ((mhpi_get(mhpiPliP, mhpiH) == mhpiVpiPli) || + (mhpi_get(mhpiPliP, mhpiH) == mhpiVhpiPli)) { + ret = mhpi_release_force(path, mhpi_mhRegion); + mhpi_release_handle(mhpiH); + if (ret == mhpiRetOk) { + return(1); + } + else + return(0); + } + else + return (0); +#endif +} + +/* + * Given a path, look the path name up using the PLI + * or the VHPI, and release it. + */ +int uvm_hdl_release(char *path) +{ + s_vpi_vecval value; + p_vpi_vecval valuep = &value; +#ifndef VCSMX +#ifdef VCSMX_FAST_UVM + vpiHandle r = vpi_handle_by_name(path, 0); + int res = uvm_hdl_set_vlog(r, path, valuep, vpiReleaseFlag); + vpi_release_handle(r); + return res; +#else + return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag); +#endif +#else +#ifndef USE_DOT_AS_HIER_SEP + mhpi_initialize('/'); +#else + mhpi_initialize('.'); +#endif +#ifdef VCSMX_FAST_UVM + mhpiHandleT h = mhpi_uvm_handle_by_name(path, 0); + mhpiReturnT ret; + + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + vpiHandle r = (vpiHandle) mhpi_get_vpi_handle(h); + int res = uvm_hdl_set_vlog(r, path, valuep, vpiReleaseFlag); + mhpi_release_handle(h); + return res; + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, h); + ret = mhpi_release_force(path, mhpi_mhRegion); + mhpi_release_handle(h); + if (ret == mhpiRetOk) { + return(1); + } + else + return(0); + + } + else { + mhpi_release_handle(h); + return (0); + } +#else + mhpiHandleT h = mhpi_handle_by_name(path, 0); + mhpiReturnT ret; + + if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) { + return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag); + } + else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) { + mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, h); + ret = mhpi_release_force(path, mhpi_mhRegion); + if (ret == mhpiRetOk) { + return(1); + } + else + return(0); + + } + else + return (0); +#endif +#endif +} + diff --git a/test_regress/t/t_uvm/dpi/uvm_hdl_xcelium.c b/test_regress/t/t_uvm/dpi/uvm_hdl_xcelium.c new file mode 100644 index 0000000000..83b0f7f48b --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_hdl_xcelium.c @@ -0,0 +1,677 @@ +//---------------------------------------------------------------------- +// Copyright 2009-2011 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- + +// use -DINCA_EXTENDED_PARTSEL_SUPPORT to use extended support for vpi_handle_by_name + +#include "vhpi_user.h" +#include "vpi_user.h" +#include "veriuser.h" +#include "svdpi.h" +#include +#include +#include + +static void m_uvm_error(const char *ID, const char *msg, ...); +static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag); +static void m_uvm_get_object_handle(const char* path, vhpiHandleT *handle,int *language); +static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag); +static int uvm_hdl_max_width(); + +// static print buffer +static char m_uvm_temp_print_buffer[1024]; + +/* + * UVM HDL access C code. + * + */ +static void m_uvm_get_object_handle(const char* path, vhpiHandleT *handle,int *language) +{ + *handle = vhpi_handle_by_name(path, 0); + + if(*handle) + *language = vhpi_get(vhpiLanguageP, *handle); +} + +// returns 0 if the name is NOT a slice +// returns 1 if the name is a slice +static int is_valid_path_slice(const char* path) { + char *path_ptr = (char *) path; + int path_len; + +#ifdef INCA_EXTENDED_PARTSEL_SUPPORT + return 0; +#endif + + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + if (*path_ptr != ']') + return 0; + + while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != ':') + return 0; + + while(path_ptr != path && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != '[') + return 0; + + return 1; +} + +static int uvm_hdl_set_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + char *path_ptr = path; + int path_len; + svLogicVecVal bit_value; + + if(!is_valid_path_slice(path)) return 0; + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + if (*path_ptr != ']') + return 0; + + while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != ':') + return 0; + + while(path_ptr != path && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != '[') + return 0; + + int lhs, rhs, width, incr; + + // extract range from path + if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) { + char index_str[20]; + int i; + path_ptr++; + path_len = (path_len - (path_ptr - path)); + incr = (lhs>rhs) ? 1 : -1; + width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1; + + // perform set for each individual bit + for (i=0; i < width; i++) { + sprintf(index_str,"%u]",rhs); + strncpy(path_ptr,index_str,path_len); + svGetPartselLogic(&bit_value,value,i,1); + rhs += incr; + if (uvm_hdl_set_vlog_partsel(path,&bit_value,flag)==0) { + if(uvm_hdl_set_vlog(path,&bit_value,flag)==0) { return 0; }; + } + } + return 1; + } + return 0; +} + + +/* + * Given a path with part-select, break into individual bit accesses + * path = pointer to user string + * value = pointer to logic vector + * flag = deposit vs force/release options, etc + */ +static int uvm_hdl_get_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + char *path_ptr = path; + int path_len; + svLogicVecVal bit_value; + + path_len = strlen(path); + path_ptr = (char*)(path+path_len-1); + + if (*path_ptr != ']') + return 0; + + while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != ':') + return 0; + + while(path_ptr != path && *path_ptr != '[') + path_ptr--; + + if (path_ptr == path || *path_ptr != '[') + return 0; + + int lhs, rhs, width, incr; + + // extract range from path + if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) { + char index_str[20]; + int i; + path_ptr++; + path_len = (path_len - (path_ptr - path)); + incr = (lhs>rhs) ? 1 : -1; + width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1; + bit_value.aval = 0; + bit_value.bval = 0; + for (i=0; i < width; i++) { + sprintf(index_str,"%u]",rhs); + strncpy(path_ptr,index_str,path_len); + + if(uvm_hdl_get_vlog_partsel(path,&bit_value,flag) == 0) { + if(uvm_hdl_get_vlog(path,&bit_value,flag)==0) { return 0; } + } + + svGetBitselLogic(&bit_value,0); + svPutPartselLogic(value,bit_value,i,1); + rhs += incr; + } + return 1; + } else { + return 0; + } +} + +static void clear_value(p_vpi_vecval value) { + int chunks; + int maxsize = uvm_hdl_max_width(); + chunks = (maxsize-1)/32 + 1; + for(int i=0;i maxsize) + { + m_uvm_error("UVM/DPI/VHDL_SET","hdl path %s is %0d bits, but the current maximum size is %0d. You may redefine it using the compile-time flag: -define UVM_HDL_MAX_WIDTH=", path, size,maxsize); + + tf_dofinish(); + } + chunks = (size-1)/32 + 1; + + value_s.format = vhpiObjTypeVal; + value_s.bufSize = 0; + value_s.value.str = NULL; + + vhpi_get_value(r, &value_s); + + switch(value_s.format) + { + case vhpiEnumVal: + { + value_s.value.enumv = vhpi2val(value[0].aval,value[0].bval); + break; + } + case vhpiEnumVecVal: + { + value_s.bufSize = size*sizeof(int); + value_s.value.enumvs = (vhpiEnumT *)malloc(size*sizeof(int)); + + vhpi_get_value(r, &value_s); + chunks = (size-1)/32 + 1; + + bit = 0; + for(i=0;i>=1; bval>>=1; + bit++; + } + } + break; + } + default: + { + m_uvm_error("UVM/DPI/VHDL_SET","Failed to set value to hdl path %s (unexpected type: %0d)", path, value_s.format); + tf_dofinish(); + return 0; + } + } + + vhpi_put_value(r, &value_s, flag); + + if(value_s.format == vhpiEnumVecVal) + { + free(value_s.value.enumvs); + } + return 1; +} + +/* + * Given a path, look the path name up using the PLI + * and return its 'value'. + */ +static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag) +{ + static int maxsize = -1; + int i, size, chunks; + vpiHandle r; + s_vpi_value value_s; + + r = vpi_handle_by_name(path, 0); + + if(r == 0) + { + m_uvm_error("UVM/DPI/VLOG_GET","unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name",path); + // Exiting is too harsh. Just return instead. + // tf_dofinish(); + return 0; + } + else + { + if(maxsize == -1) + maxsize = uvm_hdl_max_width(); + + size = vpi_get(vpiSize, r); + if(size > maxsize) + { + m_uvm_error("UVM/DPI/VLOG_GET","hdl path '%s' is %0d bits, but the maximum size is %0d. You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=", + path,size,maxsize); + //tf_dofinish(); + + vpi_release_handle(r); + + return 0; + } + chunks = (size-1)/32 + 1; + + value_s.format = vpiVectorVal; + vpi_get_value(r, &value_s); + /*dpi and vpi are reversed*/ + for(i=0;i maxsize) + { + m_uvm_error("UVM/DPI/HDL_SET","hdl path %s is %0d bits, but the maximum size is %0d, redefine using -define UVM_HDL_MAX_WIDTH=", path, size,maxsize); + tf_dofinish(); + } + chunks = (size-1)/32 + 1; + value_s.format = vhpiObjTypeVal; + value_s.bufSize = 0; + value_s.value.str = NULL; + + rtn = vhpi_get_value(r, &value_s); + + if(vhpi_check_error(0) != 0) + { + m_uvm_error("UVM/DPI/VHDL_GET","Failed to get value from hdl path %s",path); + tf_dofinish(); + return 0; + } + + switch (value_s.format) + { + case vhpiIntVal: + { + value[0].aval = value_s.value.intg; + value[0].bval = 0; + break; + } + case vhpiEnumVal: + { + switch(value_s.value.enumv) + { + case vhpiU: + case vhpiW: + case vhpiX: + { + value[0].aval = 1; value[0].bval = 1; break; + } + case vhpiZ: + { + value[0].aval = 0; value[0].bval = 1; break; + } + case vhpi0: + case vhpiL: + case vhpiDontCare: + { + value[0].aval = 0; value[0].bval = 0; break; + } + case vhpi1: + case vhpiH: + { + value[0].aval = 1; value[0].bval = 0; break; + } + } + break; + } + case vhpiEnumVecVal: + { + value_s.bufSize = size; + value_s.value.str = (char*)malloc(size); + rtn = vhpi_get_value(r, &value_s); + if (rtn > 0) { + value_s.value.str = (char*)realloc(value_s.value.str, rtn); + value_s.bufSize = rtn; + vhpi_get_value(r, &value_s); + } + for(i=0; i<((maxsize-1)/32+1); ++i) + { + value[i].aval = 0; + value[i].bval = 0; + } + bit = 0; + for(i=0;i + + +const char uvm_re_bracket_char = '/'; +#define UVM_REGEX_MAX_LENGTH 2048 +static char uvm_re[UVM_REGEX_MAX_LENGTH+4]; + +static const char* empty_regex="/^$/"; + +//-------------------------------------------------------------------- +// uvm_re_match +// +// Match a string to a regular expression. The regex is first lookup +// up in the regex cache to see if it has already been compiled. If +// so, the compile version is retrieved from the cache. Otherwise, it +// is compiled and cached for future use. After compilation the +// matching is done using regexec(). +//-------------------------------------------------------------------- +int uvm_re_match(const char * re, const char *str) +{ + regex_t *rexp; + int err; + + // safety check. Args should never be ~null~ since this is called + // from DPI. But we'll check anyway. + if(re == NULL) + return 1; + if(str == NULL) + return 1; + + int len = strlen(re); + char * rex = &uvm_re[0]; + + if (len > UVM_REGEX_MAX_LENGTH) { + const char* err_str = "uvm_re_match : regular expression greater than max %0d: |%s|"; + char buffer[strlen(err_str) + int_str_max(10) + strlen(re)]; + sprintf(buffer, err_str, UVM_REGEX_MAX_LENGTH, re); + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/REGEX_MAX", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 1; + } + + // we copy the regexp because we need to remove any brackets around it + strncpy(&uvm_re[0],re,UVM_REGEX_MAX_LENGTH); + if (len>1 && (re[0] == uvm_re_bracket_char) && re[len-1] == uvm_re_bracket_char) { + uvm_re[len-1] = '\0'; + rex++; + } + + rexp = (regex_t*)malloc(sizeof(regex_t)); + + if (rexp == NULL) { + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/REGEX_ALLOC", + (char*) "uvm_re_match: internal memory allocation error", + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return 1; + } + + err = regcomp(rexp, rex, REG_EXTENDED); + + if (err != 0) { + regerror(err,rexp,uvm_re,UVM_REGEX_MAX_LENGTH-1); + const char * err_str = "uvm_re_match : invalid glob or regular expression: |%s||%s|"; + char buffer[strlen(err_str) + strlen(re) + strlen(uvm_re)+1]; + sprintf(buffer, err_str, re, uvm_re); + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/REGEX_INV", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + regfree(rexp); + free(rexp); + return err; + } + + err = regexec(rexp, str, 0, NULL, 0); + + //vpi_printf((PLI_BYTE8*) "UVM_INFO: uvm_re_match: re=%s str=%s ERR=%0d\n",rex,str,err); + regfree(rexp); + free(rexp); + + return err; +} + + +//-------------------------------------------------------------------- +// uvm_glob_to_re +// +// Convert a glob expression to a normal regular expression. +//-------------------------------------------------------------------- + +const char * uvm_glob_to_re(const char *glob) +{ + const char *p; + int len; + + // safety check. Glob should never be ~null~ since this is called + // from DPI. But we'll check anyway. + if(glob == NULL) + return NULL; + + len = strlen(glob); + + if (len > 2040) { + const char * err_str = "uvm_re_match : glob expression greater than max 2040: |%s|"; + char buffer[strlen(err_str) + strlen(glob)+1]; + sprintf(buffer, err_str, glob); + m_uvm_report_dpi(M_UVM_ERROR, + (char*) "UVM/DPI/REGEX_MAX", + &buffer[0], + M_UVM_NONE, + (char*)__FILE__, + __LINE__); + return glob; + } + + // If either of the following cases appear then return an empty string + // + // 1. The glob string is empty (it has zero characters) + // 2. The glob string has a single character that is the + // uvm_re_bracket_char (i.e. "/") + if(len == 0 || (len == 1 && *glob == uvm_re_bracket_char)) + { + return empty_regex; + } + + // If bracketed with the /glob/, then it's already a regex + if(glob[0] == uvm_re_bracket_char && glob[len-1] == uvm_re_bracket_char) + { + strcpy(uvm_re,glob); + return &uvm_re[0]; + } + else + { + // Convert the glob to a true regular expression (Posix syntax) + len = 0; + + uvm_re[len++] = uvm_re_bracket_char; + + // ^ goes at the beginning... + if (*glob != '^') + uvm_re[len++] = '^'; + + for(p = glob; *p; p++) + { + // Replace the glob metacharacters with corresponding regular + // expression metacharacters. + switch(*p) + { + case '*': + uvm_re[len++] = '.'; + uvm_re[len++] = '*'; + break; + + case '+': + uvm_re[len++] = '.'; + uvm_re[len++] = '+'; + break; + + case '.': + uvm_re[len++] = '\\'; + uvm_re[len++] = '.'; + break; + + case '?': + uvm_re[len++] = '.'; + break; + + case '[': + uvm_re[len++] = '\\'; + uvm_re[len++] = '['; + break; + + case ']': + uvm_re[len++] = '\\'; + uvm_re[len++] = ']'; + break; + + case '(': + uvm_re[len++] = '\\'; + uvm_re[len++] = '('; + break; + + case ')': + uvm_re[len++] = '\\'; + uvm_re[len++] = ')'; + break; + + default: + uvm_re[len++] = *p; + break; + } + } + } + + // Let's check to see if the regular expression is bounded by ^ at + // the beginning and $ at the end. If not, add those characters in + // the appropriate position. + + if (uvm_re[len-1] != '$') + uvm_re[len++] = '$'; + + uvm_re[len++] = uvm_re_bracket_char; + + uvm_re[len++] = '\0'; + + return &uvm_re[0]; +} + diff --git a/test_regress/t/t_uvm/dpi/uvm_regex.svh b/test_regress/t/t_uvm/dpi/uvm_regex.svh new file mode 100644 index 0000000000..cbafaea6da --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_regex.svh @@ -0,0 +1,85 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2012 Mentor Graphics Corporation +// Copyright 2010-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- + + + +`ifndef UVM_REGEX_NO_DPI +import "DPI-C" context function int uvm_re_match(string re, string str); +import "DPI-C" context function string uvm_glob_to_re(string glob); + +`else + +// The Verilog only version does not match regular expressions, +// it only does glob style matching. +function int uvm_re_match(string re, string str); + int e, es, s, ss; + string tmp; + e = 0; s = 0; + es = 0; ss = 0; + + if(re.len() == 0) + return 0; + + // The ^ used to be used to remove the implicit wildcard, but now we don't + // use implicit wildcard so this character is just stripped. + if(re[0] == "^") + re = re.substr(1, re.len()-1); + + //This loop is only needed when the first character of the re may not + //be a *. + while (s != str.len() && re.getc(e) != "*") begin + if ((re.getc(e) != str.getc(s)) && (re.getc(e) != "?")) + return 1; + e++; s++; + end + + while (s != str.len()) begin + if (re.getc(e) == "*") begin + e++; + if (e == re.len()) begin + return 0; + end + es = e; + ss = s+1; + end + else if (re.getc(e) == str.getc(s) || re.getc(e) == "?") begin + e++; + s++; + end + else begin + e = es; + s = ss++; + end + end + while (e < re.len() && re.getc(e) == "*") + e++; + if(e == re.len()) begin + return 0; + end + else begin + return 1; + end +endfunction + +function string uvm_glob_to_re(string glob); + return glob; +endfunction + +`endif diff --git a/test_regress/t/t_uvm/dpi/uvm_svcmd_dpi.c b/test_regress/t/t_uvm/dpi/uvm_svcmd_dpi.c new file mode 100644 index 0000000000..efc791d85a --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_svcmd_dpi.c @@ -0,0 +1,135 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2011-2014 Mentor Graphics Corporation +// Copyright 2011-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// 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. +//------------------------------------------------------------------------------ + +#include "uvm_dpi.h" +#include + +#define ARGV_STACK_PTR_SIZE 32 + +// the total number of arguments (minus the -f/-F minus associated filenames) +int argc_total; +// the ptr to the array of ptrs to the args +char** argv_stack=NULL; + +char ** argv_ptr=NULL; + + +void push_data(int lvl,char *entry, int cmd) { + if(cmd==0) + argc_total++; + else + *argv_ptr++=entry; +} + +// walk one level (potentially recursive) +void walk_level(int lvl, int argc, char**argv,int cmd) { + int idx; + for(idx=0; ((lvl==0) && idx0) && (*argv));idx++,argv++) { + if(strcmp(*argv, "-f") && strcmp(*argv, "-F")) { + push_data(lvl,*argv,cmd); + } else { + argv++; + idx++; + char **n=(char**) *argv; + walk_level(lvl+1,argc,++n,cmd); + } + } +} + +const char *uvm_dpi_get_next_arg_c (int init) { + s_vpi_vlog_info info; + static int idx=0; + + if(init==1) + { + // free if necessary + free(argv_stack); + argc_total=0; + + vpi_get_vlog_info(&info); + walk_level(0,info.argc,info.argv,0); + + argv_stack = (char**) malloc (sizeof(char*)*argc_total); + argv_ptr=argv_stack; + walk_level(0,info.argc,info.argv,1); + idx=0; + argv_ptr=argv_stack; + } + + if(idx++>=argc_total) + return NULL; + + return *argv_ptr++; +} + +extern char* uvm_dpi_get_tool_name_c () +{ + s_vpi_vlog_info info; + vpi_get_vlog_info(&info); + return info.product; +} + +extern char* uvm_dpi_get_tool_version_c () +{ + s_vpi_vlog_info info; + vpi_get_vlog_info(&info); + return info.version; +} + +extern regex_t* uvm_dpi_regcomp (char* pattern) +{ + regex_t* re = (regex_t*) malloc (sizeof(regex_t)); + int status = regcomp(re, pattern, REG_NOSUB|REG_EXTENDED); + if(status) + { + const char * err_str = "uvm_dpi_regcomp : Unable to compile regex: |%s|, Element 0 is: %c"; + char buffer[strlen(err_str) + strlen(pattern) + 1]; + sprintf(buffer, err_str, pattern, pattern[0]); + m_uvm_report_dpi(M_UVM_ERROR, + (char*)"UVM/DPI/REGCOMP", + &buffer[0], + M_UVM_NONE, + (char*) __FILE__, + __LINE__); + regfree(re); + free (re); + return NULL; + } + return re; +} + +extern int uvm_dpi_regexec (regex_t* re, char* str) +{ + if(!re ) + { + return 1; + } + return regexec(re, str, (size_t)0, NULL, 0); +} + +extern void uvm_dpi_regfree (regex_t* re) +{ + if(!re) return; + regfree(re); + free (re); +} diff --git a/test_regress/t/t_uvm/dpi/uvm_svcmd_dpi.svh b/test_regress/t/t_uvm/dpi/uvm_svcmd_dpi.svh new file mode 100644 index 0000000000..885e17976f --- /dev/null +++ b/test_regress/t/t_uvm/dpi/uvm_svcmd_dpi.svh @@ -0,0 +1,65 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2013-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// 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. +//------------------------------------------------------------------------------ + +// Import DPI functions used by the interface to generate the +// lists. + +`ifndef UVM_CMDLINE_NO_DPI +import "DPI-C" function string uvm_dpi_get_next_arg_c (int init); +import "DPI-C" function string uvm_dpi_get_tool_name_c (); +import "DPI-C" function string uvm_dpi_get_tool_version_c (); + +function string uvm_dpi_get_next_arg(int init=0); + return uvm_dpi_get_next_arg_c(init); +endfunction + +function string uvm_dpi_get_tool_name(); + return uvm_dpi_get_tool_name_c(); +endfunction + +function string uvm_dpi_get_tool_version(); + return uvm_dpi_get_tool_version_c(); +endfunction + +import "DPI-C" function chandle uvm_dpi_regcomp(string regex); +import "DPI-C" function int uvm_dpi_regexec(chandle preg, string str); +import "DPI-C" function void uvm_dpi_regfree(chandle preg); + +`else +function string uvm_dpi_get_next_arg(int init=0); + return ""; +endfunction + +function string uvm_dpi_get_tool_name(); + return "?"; +endfunction + +function string uvm_dpi_get_tool_version(); + return "?"; +endfunction + + +function chandle uvm_dpi_regcomp(string regex); return null; endfunction +function int uvm_dpi_regexec(chandle preg, string str); return 0; endfunction +function void uvm_dpi_regfree(chandle preg); endfunction + +`endif diff --git a/test_regress/t/t_uvm/macros/uvm_callback_defines.svh b/test_regress/t/t_uvm/macros/uvm_callback_defines.svh index 40bfebf97d..18b92183a5 100644 --- a/test_regress/t/t_uvm/macros/uvm_callback_defines.svh +++ b/test_regress/t/t_uvm/macros/uvm_callback_defines.svh @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 -// //----------------------------------------------------------------------------- // Copyright 2007-2012 Mentor Graphics Corporation // Copyright 2010-2011 Synopsys, Inc. @@ -61,13 +59,8 @@ // @uvm-ieee 1800.2-2017 auto B.4.1 `define uvm_register_cb(T,CB) \ -///UVM static local bit m_register_cb_``CB = uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`"); \ - static local bit m_register_cb_``CB = uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`"); \ - static function void uvmt_drop_and_reregister_cb(); \ - uvm_callbacks#(T,CB)::uvmt_drop_globals(); \ - m_register_cb_``CB = uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`"); \ - endfunction -//UVM + static local bit m_register_cb_``CB = uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`"); + //----------------------------------------------------------------------------- // MACRO -- NODOCS -- `uvm_set_super_type @@ -106,7 +99,7 @@ // @uvm-ieee 1800.2-2017 auto B.4.2 `define uvm_set_super_type(T,ST) \ - static local bit m_register_``T``ST = uvm_derived_callbacks#(T,ST)::register_super_type(`"T`",`"ST`"); + static local bit m_register_``T``ST = uvm_derived_callbacks#(T,ST)::register_super_type(`"T`",`"ST`"); //----------------------------------------------------------------------------- @@ -137,7 +130,7 @@ // // A component would invoke the macro as // -//| task mycomp::run_phase(uvm_phase phase); +//| task mycomp::run_phase(uvm_phase phase); //| int curr_addr, curr_data; //| ... //| `uvm_do_callbacks(mycb, mycomp, my_function(this, curr_addr, curr_data)) @@ -218,7 +211,7 @@ // // A component would invoke the macro as // -//| task mycomp::run_phase(uvm_phase phase); +//| task mycomp::run_phase(uvm_phase phase); //| my_trans trans; //| forever begin //| get_port.get(trans); @@ -282,8 +275,8 @@ end -// The +define+UVM_CB_TRACE_ON setting will instrument the uvm library to emit -// messages with message id UVMCB_TRC and UVM_NONE verbosity +// 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. `ifdef UVM_CB_TRACE_ON diff --git a/test_regress/t/t_uvm/macros/uvm_comparer_defines.svh b/test_regress/t/t_uvm/macros/uvm_comparer_defines.svh new file mode 100644 index 0000000000..ee20c8f8d4 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_comparer_defines.svh @@ -0,0 +1,458 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// MACROS for uvm_comparer usage +// +// Provides a set of comparison macros that will call appropriate methods +// inside of a uvm_comparer object. +// +//------------------------------------------------------------------------------ + +`ifndef UVM_COMPARER_DEFINES_SVH + `define UVM_COMPARER_DEFINES_SVH + +// m_uvm_compare_threshold_begin/end +`define m_uvm_compare_threshold_begin(COMPARER) \ + if ((!COMPARER.get_threshold() || \ + (COMPARER.get_result() < COMPARER.get_threshold()))) begin \ + +`define m_uvm_compare_threshold_end \ + end + +// m_uvm_compare_begin/end +`define m_uvm_compare_begin(LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_threshold_begin(COMPARER) \ + if ((LVALUE) !== (RVALUE)) begin \ + +`define m_uvm_compare_end \ + end \ + `m_uvm_compare_threshold_end + +// uvm_compare_int +`define uvm_compare_int(LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `uvm_compare_named_int(`"LVALUE`", LVALUE, RVALUE, RADIX, COMPARER) + +`define uvm_compare_named_int(NAME, LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + if ($bits(LVALUE) <= 64) \ + void'(COMPARER.compare_field_int(NAME , LVALUE, RVALUE, $bits(LVALUE), RADIX)); \ + else \ + void'(COMPARER.compare_field(NAME , LVALUE, RVALUE, $bits(LVALUE), RADIX)); \ + `m_uvm_compare_end + +// uvm_compare_enum + +`define uvm_compare_enum(LVALUE, RVALUE, TYPE, COMPARER=comparer) \ + `uvm_compare_named_enum(`"LVALUE`", LVALUE, RVALUE, TYPE, COMPARER) + +`define uvm_compare_named_enum(NAME, LVALUE, RVALUE, TYPE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + void'(COMPARER.compare_string(NAME , \ + $sformatf("%s'(%s)", `"TYPE`", LVALUE.name()), \ + $sformatf("%s'(%s)", `"TYPE`", RVALUE.name())) ); \ + `m_uvm_compare_end + +// uvm_compare_real + +`define uvm_compare_real(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_real(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_real(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_threshold_begin(COMPARER) \ + if ((LVALUE) != (RVALUE)) begin \ + void'(COMPARER.compare_field_real(NAME , LVALUE, RVALUE)); \ + end \ + `m_uvm_compare_threshold_end + +// uvm_compare_object + +`define uvm_compare_object(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `uvm_compare_named_object(`"LVALUE`", LVALUE, RVALUE, POLICY, COMPARER) + +`define uvm_compare_named_object(NAME, LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + uvm_recursion_policy_enum prev_rec__; \ + prev_rec__ = COMPARER.get_recursion_policy(); \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(POLICY); \ + `m_uvm_compare_named_object(NAME, LVALUE, RVALUE, COMPARER) \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(prev_rec__); \ + `m_uvm_compare_end + +// This macro skips the recursion policy check, which allows it to be efficiently +// reused by other object macros. +`define m_uvm_compare_named_object(NAME, LVALUE, RVALUE, COMPARER) \ + if (COMPARER.get_recursion_policy() != UVM_REFERENCE) begin \ + bit rv; \ + uvm_policy::recursion_state_e state; \ + state = COMPARER.object_compared(LVALUE, RVALUE, COMPARER.get_recursion_policy(), rv); \ + if ((state == uvm_policy::FINISHED) && \ + !rv) \ + COMPARER.print_msg($sformatf("'%s' miscompared using saved return value", NAME)); \ + else if (state == uvm_policy::NEVER) \ + void'(COMPARER.compare_object(NAME, LVALUE, RVALUE)); \ + /* else skip to avoid infinite loop */ \ + end \ + else begin \ + void'(COMPARER.compare_object(NAME, LVALUE, RVALUE)); \ + end + + +// uvm_compare_string + +`define uvm_compare_string(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_string(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_string(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_threshold_begin(COMPARER) \ + if ((LVALUE) != (RVALUE)) begin \ + void'(COMPARER.compare_string(NAME , LVALUE, RVALUE)); \ + end \ + `m_uvm_compare_threshold_end + + +// uvm_compare_sarray_int + +`define uvm_compare_sarray_int(LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `uvm_compare_named_sarray_int(`"LVALUE`", LVALUE, RVALUE, RADIX, COMPARER) + +`define uvm_compare_named_sarray_int(NAME, LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach (LVALUE[i]) begin \ + `uvm_compare_named_int($sformatf("%s[%0d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + RADIX, \ + COMPARER) \ + end \ + `m_uvm_compare_end + +// uvm_compare_qda_int + +`define uvm_compare_qda_int(LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `uvm_compare_named_qda_int(`"LVALUE`", LVALUE, RVALUE, RADIX, COMPARER) + +`define uvm_compare_named_qda_int(NAME, LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + `uvm_compare_named_int($sformatf("%s.size()", NAME), \ + LVALUE.size(), \ + RVALUE.size(), \ + UVM_DEC, \ + COMPARER) \ + `uvm_compare_named_sarray_int(NAME, LVALUE, RVALUE, RADIX, COMPARER) \ + `m_uvm_compare_end + +// uvm_compare_sarray_real + +`define uvm_compare_sarray_real(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_sarray_real(`"LVALUE`", LVALUE, RVALUE,COMPARER) + +`define uvm_compare_named_sarray_real(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_threshold_begin(COMPARER) \ + if ((LVALUE) != (RVALUE)) begin \ + foreach (LVALUE[i]) begin \ + `uvm_compare_named_real($sformatf("%s[%0d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + end \ + `m_uvm_compare_threshold_end + +// uvm_compare_qda_real + +`define uvm_compare_qda_real(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_qda_real(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_qda_real(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_threshold_begin(COMPARER) \ + `uvm_compare_named_real($sformatf("%s.size()", NAME), \ + LVALUE.size(), \ + RVALUE.size(), \ + COMPARER) \ + `uvm_compare_named_sarray_real(NAME, LVALUE, RVALUE, COMPARER) \ + `m_uvm_compare_threshold_end + + +// uvm_compare_sarray_enum + +`define uvm_compare_sarray_enum(LVALUE, RVALUE, TYPE, COMPARER=comparer) \ + `uvm_compare_named_sarray_enum(`"LVALUE`", LVALUE, RVALUE, TYPE, COMPARER) + +`define uvm_compare_named_sarray_enum(NAME, LVALUE, RVALUE, TYPE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach (LVALUE[i]) begin \ + `uvm_compare_named_enum($sformatf("%s[%0d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + TYPE, \ + COMPARER) \ + end \ + `m_uvm_compare_end + +// uvm_compare_qda_enum + +`define uvm_compare_qda_enum(LVALUE, RVALUE, TYPE, COMPARER=comparer) \ + `uvm_compare_named_qda_enum(`"LVALUE`", LVALUE, RVALUE, TYPE, COMPARER) + +`define uvm_compare_named_qda_enum(NAME, LVALUE, RVALUE, TYPE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + `uvm_compare_named_int($sformatf("%s.size()", NAME), \ + LVALUE.size(), \ + RVALUE.size(), \ + UVM_DEC, \ + COMPARER) \ + `uvm_compare_named_sarray_enum(NAME, LVALUE, RVALUE, TYPE, COMPARER) \ + `m_uvm_compare_end + +// uvm_compare_sarray_int + +`define uvm_compare_sarray_object(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `uvm_compare_named_sarray_object(`"LVALUE`", LVALUE, RVALUE, POLICY, COMPARER) + +`define uvm_compare_named_sarray_object(NAME, LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + uvm_recursion_policy_enum prev_rec__; \ + prev_rec__ = COMPARER.get_recursion_policy(); \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(POLICY); \ + foreach (LVALUE[i]) begin \ + `m_uvm_compare_named_object($sformatf("%s[%0d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(prev_rec__); \ + `m_uvm_compare_end + +// uvm_compare_qda_int + +`define uvm_compare_qda_object(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `uvm_compare_named_qda_object(`"LVALUE`", LVALUE, RVALUE, POLICY, COMPARER) + +`define uvm_compare_named_qda_object(NAME, LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + `uvm_compare_named_int($sformatf("%s.size()", NAME), \ + LVALUE.size(), \ + RVALUE.size(), \ + UVM_DEC, \ + COMPARER) \ + `uvm_compare_named_sarray_object(NAME, LVALUE, RVALUE, POLICY, COMPARER) \ + `m_uvm_compare_end + +// uvm_compare_sarray_string + +`define uvm_compare_sarray_string(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_sarray_string(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_sarray_string(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach (LVALUE[i]) begin \ + `uvm_compare_named_string($sformatf("%s[%0d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + `m_uvm_compare_end + +// uvm_compare_qda_string + +`define uvm_compare_qda_string(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_qda_string(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_qda_string(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + `uvm_compare_named_int($sformatf("%s.size()", NAME), \ + LVALUE.size(), \ + RVALUE.size(), \ + UVM_DEC, \ + COMPARER) \ + `uvm_compare_named_sarray_string(NAME, LVALUE, RVALUE, COMPARER) \ + `m_uvm_compare_end + +// uvm_compare_aa_int_string + +`define uvm_compare_aa_int_string(LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `uvm_compare_named_aa_int_string(`"LVALUE`", LVALUE, RVALUE, RADIX, COMPARER) + +`define uvm_compare_named_aa_int_string(NAME, LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach(LVALUE[i]) begin \ + if (!RVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%s' not in RHS", NAME, i)); \ + end \ + else begin \ + `uvm_compare_named_int($sformatf("%s[%s]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + RADIX, \ + COMPARER) \ + end \ + end \ + foreach(RVALUE[i]) begin \ + if(!LVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%s' not in LHS", NAME, i)); \ + end \ + end \ + `m_uvm_compare_end + +// uvm_compare_aa_object_string + +`define uvm_compare_aa_object_string(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `uvm_compare_named_aa_object_string(`"LVALUE`", LVALUE, RVALUE, POLICY, COMPARER) + +`define uvm_compare_named_aa_object_string(NAME, LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + uvm_recursion_policy_enum prev_rec__; \ + prev_rec__ = COMPARER.get_recursion_policy(); \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(POLICY); \ + foreach(LVALUE[i]) begin \ + if (!RVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%s' not in RHS", NAME, i)); \ + end \ + else begin \ + `m_uvm_compare_named_object($sformatf("%s[%s]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + end \ + foreach(RVALUE[i]) begin \ + if(!LVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%s' not in LHS", NAME, i)); \ + end \ + end \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(prev_rec__); \ + `m_uvm_compare_end + +// uvm_compare_aa_string_string + +`define uvm_compare_aa_string_string(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_aa_string_string(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_aa_string_string(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach(LVALUE[i]) begin \ + if (!RVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%s' not in RHS", NAME, i)); \ + end \ + else begin \ + `uvm_compare_named_string($sformatf("%s[%s]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + end \ + foreach(RVALUE[i]) begin \ + if(!LVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%s' not in LHS", NAME, i)); \ + end \ + end \ + `m_uvm_compare_end + +// uvm_compare_aa_int_int + +`define uvm_compare_aa_int_int(LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `uvm_compare_named_aa_int_int(`"LVALUE`", LVALUE, RVALUE, RADIX, COMPARER) + +`define uvm_compare_named_aa_int_int(NAME, LVALUE, RVALUE, RADIX, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach(LVALUE[i]) begin \ + if (!RVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%0d' not in RHS", NAME, i)); \ + end \ + else begin \ + `uvm_compare_named_int($sformatf("%s[%d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + RADIX, \ + COMPARER) \ + end \ + end \ + foreach(RVALUE[i]) begin \ + if(!LVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%0d' not in LHS", NAME, i)); \ + end \ + end \ + `m_uvm_compare_end + +// uvm_compare_aa_object_int + +`define uvm_compare_aa_object_int(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `uvm_compare_named_aa_object_int(`"LVALUE`", LVALUE, RVALUE, POLICY, COMPARER) + +`define uvm_compare_named_aa_object_int(NAME, LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + uvm_recursion_policy_enum prev_rec__; \ + prev_rec__ = COMPARER.get_recursion_policy(); \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(POLICY); \ + foreach(LVALUE[i]) begin \ + if (!RVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%0d' not in RHS", NAME, i)); \ + end \ + else begin \ + `m_uvm_compare_named_object($sformatf("%s[%s]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + end \ + foreach(RVALUE[i]) begin \ + if(!LVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%0d' not in LHS", NAME, i)); \ + end \ + end \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COMPARER.set_recursion_policy(prev_rec__); \ + `m_uvm_compare_end + +// uvm_compare_aa_string_int + +`define uvm_compare_aa_string_int(LVALUE, RVALUE, COMPARER=comparer) \ + `uvm_compare_named_aa_string_int(`"LVALUE`", LVALUE, RVALUE, COMPARER) + +`define uvm_compare_named_aa_string_int(NAME, LVALUE, RVALUE, COMPARER=comparer) \ + `m_uvm_compare_begin(LVALUE, RVALUE, COMPARER) \ + foreach(LVALUE[i]) begin \ + if (!RVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%d' not in RHS", NAME, i)); \ + end \ + else begin \ + `uvm_compare_named_string($sformatf("%s[%d]", NAME, i), \ + LVALUE[i], \ + RVALUE[i], \ + COMPARER) \ + end \ + end \ + foreach(RVALUE[i]) begin \ + if(!LVALUE.exists(i)) begin \ + COMPARER.print_msg($sformatf("%s: Key '%d' not in LHS", NAME, i)); \ + end \ + end \ + `m_uvm_compare_end + +`endif // UVM_COMPARER_DEFINES_SVH diff --git a/test_regress/t/t_uvm/macros/uvm_copier_defines.svh b/test_regress/t/t_uvm/macros/uvm_copier_defines.svh new file mode 100644 index 0000000000..bbd582d2b0 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_copier_defines.svh @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Qualcomm, Inc. +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// MACROS for uvm_copier usage +// +// Provides a set of comparison macros that will call appropriate methods +// inside of a uvm_copier object. +// +//------------------------------------------------------------------------------ + +`ifndef UVM_COPIER_DEFINES_SVH + `define UVM_COPIER_DEFINES_SVH + +// uvm_copy_object + +`define uvm_copy_object(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COPIER=copier) \ +if (LVALUE != RVALUE) begin \ + if ((RVALUE == null) || \ + (POLICY == UVM_REFERENCE) || \ + ((POLICY == UVM_DEFAULT_POLICY) && \ + (COPIER.get_recursion_policy() == UVM_REFERENCE))) begin \ + LVALUE = RVALUE; \ + end \ + else begin \ + uvm_object lvalue_ref__; \ + if (!COPIER.get_first_copy(RVALUE,lvalue_ref__) || !$cast(LVALUE,lvalue_ref__)) begin \ + uvm_recursion_policy_enum prev_pol__ = COPIER.get_recursion_policy(); \ + uvm_recursion_policy_enum curr_pol__; \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COPIER.set_recursion_policy(POLICY); \ + curr_pol__ = COPIER.get_recursion_policy(); \ + if (LVALUE == null) begin \ + if (($cast(LVALUE, RVALUE.create(RVALUE.get_name())) == 0) || \ + (LVALUE == null)) begin \ + `uvm_fatal("UVM/COPY/NULL_CREATE", \ + {"Could not create '", RVALUE.get_full_name(), \ + "' of type '", RVALUE.get_type_name(), \ + "', into '", `"LVALUE`", "'."}) \ + end \ + else begin \ + COPIER.copy_object(LVALUE, RVALUE); \ + end \ + end \ + else begin \ + if (COPIER.object_copied(LVALUE, RVALUE, curr_pol__) == uvm_policy::STARTED) begin \ + `uvm_warning("UVM/COPY/LOOP", \ + {"Loop detected in copy operation (LHS:'", \ + LVALUE.get_full_name(), \ + "', RHS:'", \ + RVALUE.get_full_name(), \ + "')"}) \ + end \ + else begin \ + COPIER.copy_object(LVALUE, RVALUE); \ + end \ + end \ + if (POLICY != UVM_DEFAULT_POLICY) \ + COPIER.set_recursion_policy(prev_pol__); \ + end \ + end \ +end + +`define uvm_copy_aa_object(LVALUE, RVALUE, POLICY=UVM_DEFAULT_POLICY, COPIER=copier) \ +if ((POLICY == UVM_REFERENCE) || !RVALUE.size()) \ + LVALUE = RVALUE; \ +else begin \ + LVALUE.delete(); \ + foreach(RVALUE[i]) \ + `uvm_copy_object(LVALUE[i], RVALUE[i], POLICY, COPIER) \ +end + + +`define uvm_copier_get_function(FUNCTION) \ +function int get_``FUNCTION``_copy(uvm_object rhs, ref uvm_object lhs); \ + if (m_recur_states.exists(rhs)) \ + return m_recur_states[rhs].FUNCTION(lhs); \ + return 0; \ +endfunction : get_``FUNCTION``_copy + +`endif // UVM_COPIER_DEFINES_SVH diff --git a/test_regress/t/t_uvm/macros/uvm_global_defines.svh b/test_regress/t/t_uvm/macros/uvm_global_defines.svh new file mode 100644 index 0000000000..5b4cf2c410 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_global_defines.svh @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------------ +// Copyright 2014 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2015 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_GLOBAL_DEFINES_SVH +`define UVM_GLOBAL_DEFINES_SVH + +// +// Title -- NODOCS -- Global Macros +//------------------------ +// Group -- NODOCS -- Global object Macro definitions can be used in multiple locations +//------------------------ +// +// MACRO -- NODOCS -- `UVM_MAX_STREAMBITS +// +// Defines the maximum bit vector size for integral types. +// Used to set uvm_bitstream_t + +`ifndef UVM_MAX_STREAMBITS + // @uvm-ieee 1800.2-2017 auto 16.2.3.8 + // @uvm-ieee 1800.2-2017 auto 16.4.6.1 + // @uvm-ieee 1800.2-2017 auto 16.5.4.8 + // @uvm-ieee 1800.2-2017 auto B.6.2 + `define UVM_MAX_STREAMBITS 4096 +`endif + + +// MACRO -- NODOCS -- `UVM_PACKER_MAX_BYTES +// +// Defines the maximum bytes to allocate for packing an object using +// the . Default is <`UVM_MAX_STREAMBITS>, in ~bytes~. + +`ifndef UVM_PACKER_MAX_BYTES + `define UVM_PACKER_MAX_BYTES `UVM_MAX_STREAMBITS +`endif + +//------------------------ +// Group -- NODOCS -- Global Time Macro definitions that can be used in multiple locations +//------------------------ + +// MACRO -- NODOCS -- `UVM_DEFAULT_TIMEOUT +// +// The default timeout for simulation, if not overridden by +// or +// + +`define UVM_DEFAULT_TIMEOUT 9200s + +`endif // `ifndef UVM_GLOBAL_DEFINES_SVH diff --git a/test_regress/t/t_uvm/macros/uvm_message_defines.svh b/test_regress/t/t_uvm/macros/uvm_message_defines.svh new file mode 100644 index 0000000000..f25f8432dd --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_message_defines.svh @@ -0,0 +1,548 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2014-2015 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +//---------------------------------------------------------------------- + +`ifndef UVM_MESSAGE_DEFINES_SVH +`define UVM_MESSAGE_DEFINES_SVH + +`ifndef UVM_LINE_WIDTH + `define UVM_LINE_WIDTH 120 +`endif + +`ifndef UVM_NUM_LINES + `define UVM_NUM_LINES 120 +`endif + +//`ifndef UVM_USE_FILE_LINE +//`define UVM_REPORT_DISABLE_FILE_LINE +//`endif + +`ifdef UVM_REPORT_DISABLE_FILE_LINE +`define UVM_REPORT_DISABLE_FILE +`define UVM_REPORT_DISABLE_LINE +`endif + +`ifdef UVM_REPORT_DISABLE_FILE +`define uvm_file "" +`else +`define uvm_file `__FILE__ +`endif + +`ifdef UVM_REPORT_DISABLE_LINE +`define uvm_line 0 +`else +`define uvm_line `__LINE__ +`endif + + +//------------------------------------------------------------------------------ +// +// Title -- NODOCS -- Report Macros +// +// This set of macros provides wrappers around the uvm_report_* +// functions. The macros serve two essential purposes: +// +// - To reduce the processing overhead associated with filtered out messages, +// a check is made against the report's verbosity setting and the action +// for the id/severity pair before any string formatting is performed. This +// affects only `uvm_info reports. +// +// - The `__FILE__ and `__LINE__ information is automatically provided to the +// underlying uvm_report_* call. Having the file and line number from where +// a report was issued aides in debug. You can disable display of file and +// line information in reports by defining UVM_REPORT_DISABLE_FILE_LINE on +// the command line. +// +// The macros also enforce a verbosity setting of UVM_NONE for warnings, errors +// and fatals so that they cannot be mistakenly turned off by setting the +// verbosity level too low (warning and errors can still be turned off by +// setting the actions appropriately). +// +// To use the macros, replace the previous call to uvm_report_* with the +// corresponding macro. +// +//| //Previous calls to uvm_report_* +//| uvm_report_info("MYINFO1", $sformatf("val: %0d", val), UVM_LOW); +//| uvm_report_warning("MYWARN1", "This is a warning"); +//| uvm_report_error("MYERR", "This is an error"); +//| uvm_report_fatal("MYFATAL", "A fatal error has occurred"); +// +// The above code is replaced by +// +//| //New calls to `uvm_* +//| `uvm_info("MYINFO1", $sformatf("val: %0d", val), UVM_LOW) +//| `uvm_warning("MYWARN1", "This is a warning") +//| `uvm_error("MYERR", "This is an error") +//| `uvm_fatal("MYFATAL", "A fatal error has occurred") +// +// Macros represent text substitutions, not statements, so they should not be +// terminated with semi-colons. + + +//---------------------------------------------------------------------------- +// Group -- NODOCS -- Basic Messaging Macros +//---------------------------------------------------------------------------- + + +// MACRO -- NODOCS -- `uvm_info +// +// Calls uvm_report_info if ~VERBOSITY~ is lower than the configured verbosity of +// the associated reporter. ~ID~ is given as the message tag and ~MSG~ is given as +// the message text. The file and line are also sent to the uvm_report_info call. +// +// |`uvm_info(ID, MSG, VERBOSITY) + +// @uvm-ieee 1800.2-2017 auto B.1.1.1 +`define uvm_info(ID, MSG, VERBOSITY) \ + begin \ + if (uvm_report_enabled(VERBOSITY,UVM_INFO,ID)) \ + uvm_report_info (ID, MSG, VERBOSITY, `uvm_file, `uvm_line, "", 1); \ + end + + +// MACRO -- NODOCS -- `uvm_warning +// +// Calls uvm_report_warning with a verbosity of UVM_NONE. The message cannot +// be turned off using the reporter's verbosity setting, but can be turned off +// by setting the action for the message. ~ID~ is given as the message tag and +// ~MSG~ is given as the message text. The file and line are also sent to the +// uvm_report_warning call. +// +// |`uvm_warning(ID, MSG) + +// @uvm-ieee 1800.2-2017 auto B.1.1.2 +`define uvm_warning(ID, MSG) \ + begin \ + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,ID)) \ + uvm_report_warning (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end + + +// MACRO -- NODOCS -- `uvm_error +// +// Calls uvm_report_error with a verbosity of UVM_NONE. The message cannot +// be turned off using the reporter's verbosity setting, but can be turned off +// by setting the action for the message. ~ID~ is given as the message tag and +// ~MSG~ is given as the message text. The file and line are also sent to the +// uvm_report_error call. +// +// |`uvm_error(ID, MSG) + +// @uvm-ieee 1800.2-2017 auto B.1.1.3 +`define uvm_error(ID, MSG) \ + begin \ + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,ID)) \ + uvm_report_error (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end + + +// MACRO -- NODOCS -- `uvm_fatal +// +// Calls uvm_report_fatal with a verbosity of UVM_NONE. The message cannot +// be turned off using the reporter's verbosity setting, but can be turned off +// by setting the action for the message. ~ID~ is given as the message tag and +// ~MSG~ is given as the message text. The file and line are also sent to the +// uvm_report_fatal call. +// +// |`uvm_fatal(ID, MSG) + +// @uvm-ieee 1800.2-2017 auto B.1.1.4 +`define uvm_fatal(ID, MSG) \ + begin \ + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,ID)) \ + uvm_report_fatal (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end + + + +// MACRO -- NODOCS -- `uvm_info_context +// +//| `uvm_info_context(ID, MSG, VERBOSITY, RO) +// +// Operates identically to `uvm_info but requires that the +// context, or , in which the message is printed be +// explicitly supplied as a macro argument. + +// @uvm-ieee 1800.2-2017 auto B.1.1.5 +`define uvm_info_context(ID, MSG, VERBOSITY, RO) \ + begin \ + if (RO.uvm_report_enabled(VERBOSITY,UVM_INFO,ID)) \ + RO.uvm_report_info (ID, MSG, VERBOSITY, `uvm_file, `uvm_line, "", 1); \ + end + + +// MACRO -- NODOCS -- `uvm_warning_context +// +//| `uvm_warning_context(ID, MSG, RO) +// +// Operates identically to `uvm_warning but requires that the +// context, or , in which the message is printed be +// explicitly supplied as a macro argument. + +// @uvm-ieee 1800.2-2017 auto B.1.1.6 +`define uvm_warning_context(ID, MSG, RO) \ + begin \ + if (RO.uvm_report_enabled(UVM_NONE,UVM_WARNING,ID)) \ + RO.uvm_report_warning (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end + + +// MACRO -- NODOCS -- `uvm_error_context +// +//| `uvm_error_context(ID, MSG, RO) +// +// Operates identically to `uvm_error but requires that the +// context, or in which the message is printed be +// explicitly supplied as a macro argument. + +// @uvm-ieee 1800.2-2017 auto B.1.1.7 +`define uvm_error_context(ID, MSG, RO) \ + begin \ + if (RO.uvm_report_enabled(UVM_NONE,UVM_ERROR,ID)) \ + RO.uvm_report_error (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end + + +// MACRO -- NODOCS -- `uvm_fatal_context +// +//| `uvm_fatal_context(ID, MSG, RO) +// +// Operates identically to `uvm_fatal but requires that the +// context, or , in which the message is printed be +// explicitly supplied as a macro argument. + +// @uvm-ieee 1800.2-2017 auto B.1.1.8 +`define uvm_fatal_context(ID, MSG, RO) \ + begin \ + if (RO.uvm_report_enabled(UVM_NONE,UVM_FATAL,ID)) \ + RO.uvm_report_fatal (ID, MSG, UVM_NONE, `uvm_file, `uvm_line, "", 1); \ + end + + + + +//---------------------------------------------------------------------------- +// Group -- NODOCS -- Message Trace Macros +//---------------------------------------------------------------------------- + +// MACRO- `uvm_message_begin +// +// Undocumented. Library internal use. +// + +`define uvm_message_begin(SEVERITY, ID, MSG, VERBOSITY, FILE, LINE, RM) \ + begin \ + if (uvm_report_enabled(VERBOSITY,SEVERITY,ID)) begin \ + uvm_report_message __uvm_msg; \ + if (RM == null) RM = uvm_report_message::new_report_message(); \ + __uvm_msg = RM; \ + __uvm_msg.set_report_message(SEVERITY, ID, MSG, VERBOSITY, FILE, LINE, ""); + + +// MACRO- `uvm_message_end +// +// Undocumented. Library internal use. +// +// + +`define uvm_message_end \ + uvm_process_report_message(__uvm_msg); \ + end \ + end + +// MACRO- `uvm_message_context_begin +// +// Undocumented. Library internal use. +// + +`define uvm_message_context_begin(SEVERITY, ID, MSG, VERBOSITY, FILE, LINE, RO, RM) \ + begin \ + uvm_report_object __report_object; \ + __report_object = RO; \ + if (__report_object.uvm_report_enabled(VERBOSITY,SEVERITY,ID)) begin \ + uvm_report_message __uvm_msg; \ + if (RM == null) RM = uvm_report_message::new_report_message(); \ + __uvm_msg = RM; \ + __uvm_msg.set_report_message(SEVERITY, ID, MSG, VERBOSITY, FILE, LINE, ""); + + +// MACRO- `uvm_message_context_end +// +// Undocumented. Library internal use. +// +// + +`define uvm_message_context_end \ + __report_object.uvm_process_report_message(__uvm_msg); \ + end \ + end + + +// MACRO -- NODOCS -- `uvm_info_begin +// +// |`uvm_info_begin(ID, MSG, VERBOSITY, RM = __uvm_msg) +// + +`define uvm_info_begin(ID, MSG, VERBOSITY, RM = __uvm_msg) \ + `uvm_message_begin(UVM_INFO, ID, MSG, VERBOSITY, `uvm_file, `uvm_line, RM) + +// MACRO -- NODOCS -- `uvm_info_end +// +// This macro pair provides the ability to add elements to messages. +// +// |`uvm_info_end +// +// Example usage is shown here. +// +// |... +// |task my_task(); +// | ... +// | `uvm_info_begin("MY_ID", "This is my message...", UVM_LOW) +// | `uvm_message_add_tag("my_color", "red") +// | `uvm_message_add_int(my_int, UVM_DEC) +// | `uvm_message_add_string(my_string) +// | `uvm_message_add_object(my_obj) +// | `uvm_info_end +// | ... +// |endtask +// + +`define uvm_info_end \ + `uvm_message_end + + +// MACRO -- NODOCS -- `uvm_warning_begin +// +// |`uvm_warning_begin(ID, MSG, RM = __uvm_msg) +// + +`define uvm_warning_begin(ID, MSG, RM = __uvm_msg) \ + `uvm_message_begin(UVM_WARNING, ID, MSG, UVM_NONE, `uvm_file, `uvm_line, RM) + +// MACRO -- NODOCS -- `uvm_warning_end +// +// This macro pair operates identically to <`uvm_info_begin>/<`uvm_info_end> with +// exception that the message severity is and has no verbosity threshold. +// +// |`uvm_warning_end +// +// The usage shown in <`uvm_info_end> works identically for this pair. +// + +`define uvm_warning_end \ + `uvm_message_end + + +// MACRO -- NODOCS -- `uvm_error_begin +// +// |`uvm_error_begin(ID, MSG, RM = __uvm_msg) +// + +`define uvm_error_begin(ID, MSG, RM = __uvm_msg) \ + `uvm_message_begin(UVM_ERROR, ID, MSG, UVM_NONE, `uvm_file, `uvm_line, RM) + + +// MACRO -- NODOCS -- `uvm_error_end +// +// This macro pair operates identically to <`uvm_info_begin>/<`uvm_info_end> with +// exception that the message severity is and has no verbosity threshold. +// +// |`uvm_error_end +// +// The usage shown in <`uvm_info_end> works identically for this pair. +// + +`define uvm_error_end \ + `uvm_message_end + + +// MACRO -- NODOCS -- `uvm_fatal_begin +// +// |`uvm_fatal_begin(ID, MSG, RM = __uvm_msg) +// + +`define uvm_fatal_begin(ID, MSG, RM = __uvm_msg) \ + `uvm_message_begin(UVM_FATAL, ID, MSG, UVM_NONE, `uvm_file, `uvm_line, RM) + + +// MACRO -- NODOCS -- `uvm_fatal_end +// +// This macro pair operates identically to <`uvm_info_begin>/<`uvm_info_end> with +// exception that the message severity is and has no verbosity threshold. +// +// |`uvm_fatal_end +// +// The usage shown in <`uvm_info_end> works identically for this pair. +// + +`define uvm_fatal_end \ + `uvm_message_end + + +// MACRO -- NODOCS -- `uvm_info_context_begin +// +// |`uvm_info_context_begin(ID, MSG, UVM_NONE, RO, RM = __uvm_msg) +// + +`define uvm_info_context_begin(ID, MSG, VERBOSITY, RO, RM = __uvm_msg) \ + `uvm_message_context_begin(UVM_INFO, ID, MSG, VERBOSITY, `uvm_file, `uvm_line, RO, RM) + + +// MACRO -- NODOCS -- `uvm_info_context_end +// +// |`uvm_info_context_end +// +// This macro pair operates identically to <`uvm_info_begin>/<`uvm_info_end>, but +// requires that the context, or in which the message is printed +// be explicitly supplied as a macro argument. +// + +`define uvm_info_context_end \ + `uvm_message_context_end + + +// MACRO -- NODOCS -- `uvm_warning_context_begin +// +// |`uvm_warning_context_begin(ID, MSG, RO, RM = __uvm_msg) +// + +`define uvm_warning_context_begin(ID, MSG, RO, RM = __uvm_msg) \ + `uvm_message_context_begin(UVM_WARNING, ID, MSG, UVM_NONE, `uvm_file, `uvm_line, RO, RM) + +// MACRO -- NODOCS -- `uvm_warning_context_end +// +// |`uvm_warning_context_end +// +// This macro pair operates identically to <`uvm_warning_begin>/<`uvm_warning_end>, but +// requires that the context, or in which the message is printed +// be explicitly supplied as a macro argument. +// + +`define uvm_warning_context_end \ + `uvm_message_context_end + + +// MACRO -- NODOCS -- `uvm_error_context_begin +// +// |`uvm_error_context_begin(ID, MSG, RO, RM = __uvm_msg) +// + +`define uvm_error_context_begin(ID, MSG, RO, RM = __uvm_msg) \ + `uvm_message_context_begin(UVM_ERROR, ID, MSG, UVM_NONE, `uvm_file, `uvm_line, RO, RM) + + +// MACRO -- NODOCS -- `uvm_error_context_end +// +// |`uvm_error_context_end +// +// This macro pair operates identically to <`uvm_error_begin>/<`uvm_error_end>, but +// requires that the context, or in which the message is printed +// be explicitly supplied as a macro argument. +// + +`define uvm_error_context_end \ + `uvm_message_context_end + + +// MACRO -- NODOCS -- `uvm_fatal_context_begin +// +// |`uvm_fatal_context_begin(ID, MSG, RO, RM = __uvm_msg) +// + +`define uvm_fatal_context_begin(ID, MSG, RO, RM = __uvm_msg) \ + `uvm_message_context_begin(UVM_FATAL, ID, MSG, UVM_NONE, `uvm_file, `uvm_line, RO, RM) + + +// MACRO -- NODOCS -- `uvm_fatal_context_end +// +// |`uvm_fatal_context_end +// +// This macro pair operates identically to <`uvm_fatal_begin>/<`uvm_fatal_end>, but +// requires that the context, or in which the message is printed +// be explicitly supplied as a macro argument. +// + +`define uvm_fatal_context_end \ + `uvm_message_context_end + + +//---------------------------------------------------------------------------- +// Group -- NODOCS -- Message Element Macros +//---------------------------------------------------------------------------- + + +// MACRO -- NODOCS -- `uvm_message_add_tag +// +// |`uvm_message_add_tag(NAME, VALUE, ACTION=(UVM_LOG|UVM_RM_RECORD)) +// + +`define uvm_message_add_tag(NAME, VALUE, ACTION=(UVM_LOG|UVM_RM_RECORD)) \ + __uvm_msg.add_string(NAME, VALUE, ACTION); + + +// MACRO -- NODOCS -- `uvm_message_add_int +// +// |`uvm_message_add_int(VAR, RADIX, LABEL = "", ACTION=(UVM_LOG|UVM_RM_RECORD)) +// + +`define uvm_message_add_int(VAR, RADIX, LABEL="", ACTION=(UVM_LOG|UVM_RM_RECORD)) \ + if (LABEL == "") \ + __uvm_msg.add_int(`"VAR`", VAR, $bits(VAR), RADIX, ACTION); \ + else \ + __uvm_msg.add_int(LABEL, VAR, $bits(VAR), RADIX, ACTION); + + +// MACRO -- NODOCS -- `uvm_message_add_string +// +// |`uvm_message_add_string(VAR, LABEL = "", ACTION=(UVM_LOG|UVM_RM_RECORD)) +// + +`define uvm_message_add_string(VAR, LABEL="", ACTION=(UVM_LOG|UVM_RM_RECORD)) \ + if (LABEL == "") \ + __uvm_msg.add_string(`"VAR`", VAR, ACTION); \ + else \ + __uvm_msg.add_string(LABEL, VAR, ACTION); + + +// MACRO -- NODOCS -- `uvm_message_add_object +// +// These macros allow the user to provide elements that are associated with +// s. Separate macros are provided such that the +// user can supply arbitrary string/string pairs using <`uvm_message_add_tag>, +// integral types along with a radix using <`uvm_message_add_int>, string +// using <`uvm_message_add_string> and s using +// <`uvm_message_add_object>. +// +// |`uvm_message_add_object(VAR, LABEL = "", ACTION=(UVM_LOG|UVM_RM_RECORD)) +// +// Example usage is shown in <`uvm_info_end>. +// + +`define uvm_message_add_object(VAR, LABEL="", ACTION=(UVM_LOG|UVM_RM_RECORD)) \ + if (LABEL == "") \ + __uvm_msg.add_object(`"VAR`", VAR, ACTION); \ + else \ + __uvm_msg.add_object(LABEL, VAR, ACTION); + + +`endif //UVM_MESSAGE_DEFINES_SVH diff --git a/test_regress/t/t_uvm/macros/uvm_object_defines.svh b/test_regress/t/t_uvm/macros/uvm_object_defines.svh index c324634322..8e55550966 100644 --- a/test_regress/t/t_uvm/macros/uvm_object_defines.svh +++ b/test_regress/t/t_uvm/macros/uvm_object_defines.svh @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 -// //------------------------------------------------------------------------------ // Copyright 2012 Aldec // Copyright 2007-2012 Mentor Graphics Corporation @@ -167,7 +165,7 @@ // for an abstract class (i.e. virtual class). // Implementation Note: The `uvm_field_utils_begin macro creates a new local -// function "__m_uvm_execute_field_op", which has a similar signature to +// function "__m_uvm_execute_field_op", which has a similar signature to // , but the arguments are named differently so as to prevent // potential collisions with field names. For example, if the user had a // field named "op", then that could collide with the "op" argument of the @@ -295,7 +293,7 @@ endfunction : __m_uvm_execute_field_op // @uvm-ieee 1800.2-2017 auto B.2.1 // @uvm-ieee 1800.2-2017 auto B.2.1.2 `define uvm_object_utils(T) \ -//UVM `m_uvm_object_registry_internal(T,T) \ + `m_uvm_object_registry_internal(T,T) \ `m_uvm_object_create_func(T) \ `uvm_type_name_decl(`"T`") @@ -2085,7 +2083,7 @@ UVM_``OP: \ // @uvm-ieee 1800.2-2017 auto B.2.2.6.1 `define uvm_field_aa_object_int(ARG,FLAG=UVM_DEFAULT) \ `uvm_field_aa_object_key(int, ARG, FLAG) - + // Not LRM, but supports packing + configuration `define uvm_field_aa_object_key(KEY, ARG,FLAG=UVM_DEFAULT) \ `m_uvm_field_begin(ARG, FLAG) \ diff --git a/test_regress/t/t_uvm/macros/uvm_packer_defines.svh b/test_regress/t/t_uvm/macros/uvm_packer_defines.svh new file mode 100644 index 0000000000..a0d1cadac7 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_packer_defines.svh @@ -0,0 +1,613 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Qualcomm, Inc. +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 NVIDIA Corporation +// Copyright 2018 Cisco Systems, 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. +//---------------------------------------------------------------------- + +`ifndef UVM_PACKER_DEFINES_SVH + `define UVM_PACKER_DEFINES_SVH + +//------------------------------------------------------------------------------ +// +// MACROS for uvm_packer usage +// +// Provides a set of packing/unpacking macros that will call appropriate methods +// inside of a uvm_packer object. +// +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Group -- NODOCS -- Packing Macros +// +// The packing macros assist users who implement the +// method. They help ensure that the pack operation is the exact inverse of the +// unpack operation. See also . +// +//| virtual function void do_pack(uvm_packer packer); +//| `uvm_pack_int(cmd) +//| `uvm_pack_int(addr) +//| `uvm_pack_array(data) +//| endfunction +// +// The 'N' versions of these macros take a explicit size argument, which must +// be compile-time constant value greater than 0. +//------------------------------------------------------------------------------ + +//-------------------------------- +// Group -- NODOCS -- Packing - With Size Info +//-------------------------------- + +// Macro -- NODOCS -- `uvm_pack_intN +// +// Pack an integral variable. +// +//| `uvm_pack_intN(VAR,SIZE) +// + +// Group: Packing Macros +// +// The packing macros are implemented as described in section B.2.4 of the +// 1800.2 specification. +// +// The Accellera implementation adds an additional ~PACKER~ argument to +// these macros with a default value of 'packer'. This allows the macros +// to be used in environments with alternative packer names. +// +// For example, <`uvm_pack_intN> is defined in the LRM as +// | `define uvm_pack_intN(VAR,SIZE) +// +// Whereas the implementation is +// | `define uvm_pack_intN(VAR,SIZE,PACKER=packer) +// +// This allows for usage such as +// | function void pack_foo( uvm_packer other_packer ); +// | `uvm_pack_intN(foo, 32, other_packer) +// | endfunction : pack_foo +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 + + +// @uvm-ieee 1800.2-2017 auto B.2.4.1 +`define uvm_pack_intN(VAR,SIZE,PACKER=packer) \ + begin \ + bit __array[]; \ + { << bit { __array}} = VAR; \ + __array = new [SIZE] (__array); \ + PACKER.pack_bits(__array, SIZE); \ + end + +// @uvm-ieee 1800.2-2017 auto B.2.4.2 +`define uvm_pack_enumN(VAR,SIZE,PACKER=packer) \ + `uvm_pack_intN(VAR,SIZE,PACKER) + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.3 +`define uvm_pack_sarrayN(VAR,SIZE,PACKER=packer) \ + begin \ + foreach (VAR `` [index]) \ + `uvm_pack_intN(VAR[index],SIZE,PACKER) \ + end + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.4 +`define uvm_pack_arrayN(VAR,SIZE,PACKER=packer) \ + begin \ + `uvm_pack_intN(VAR.size(),32,PACKER) \ + `uvm_pack_sarrayN(VAR,SIZE,PACKER) \ + end + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.5 +`define uvm_pack_queueN(VAR,SIZE,PACKER=packer) \ + `uvm_pack_arrayN(VAR,SIZE,PACKER) + + +//------------------------------ +// Group -- NODOCS -- Packing - No Size Info +//------------------------------ + + +// @uvm-ieee 1800.2-2017 auto B.2.4.6 +`define uvm_pack_int(VAR,PACKER=packer) \ + `uvm_pack_intN(VAR,$bits(VAR),PACKER) + +// uvm_pack_object +`define uvm_pack_object(VAR,PACKER=packer) \ + PACKER.pack_object_with_meta(VAR); + +// @uvm-ieee 1800.2-2017 auto B.2.4.7 +`define uvm_pack_enum(VAR,PACKER=packer) \ + `uvm_pack_enumN(VAR,$bits(VAR),PACKER) + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.8 +`define uvm_pack_string(VAR,PACKER=packer) \ + PACKER.pack_string(VAR); + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.9 +`define uvm_pack_real(VAR,PACKER=packer) \ + PACKER.pack_real(VAR); + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.10 +`define uvm_pack_sarray(VAR,PACKER=packer) \ + `uvm_pack_sarrayN(VAR,$bits(VAR[0]),PACKER) + + + +// @uvm-ieee 1800.2-2017 auto B.2.4.11 +`define uvm_pack_array(VAR,PACKER=packer) \ + `uvm_pack_arrayN(VAR,$bits(VAR[0]),PACKER) + +`define uvm_pack_da(VAR,PACKER=packer) \ + `uvm_pack_array(VAR,PACKER) + +// @uvm-ieee 1800.2-2017 auto B.2.4.12 +`define uvm_pack_queue(VAR,PACKER=packer) \ + `uvm_pack_queueN(VAR,$bits(VAR[0]),PACKER) + +//------------------------------------------------------------------------------ +// Group -- NODOCS -- Unpacking Macros +// +// The unpacking macros assist users who implement the +// method. They help ensure that the unpack operation is the exact inverse of +// the pack operation. See also . +// +//| virtual function void do_unpack(uvm_packer packer); +//| `uvm_unpack_enum(cmd,cmd_t) +//| `uvm_unpack_int(addr) +//| `uvm_unpack_array(data) +//| endfunction +// +// The 'N' versions of these macros take a explicit size argument, which must +// be a compile-time constant value greater than 0. +//------------------------------------------------------------------------------ + +//---------------------------------- +// Group -- NODOCS -- Unpacking - With Size Info +//---------------------------------- + + +// @uvm-ieee 1800.2-2017 auto B.2.5.1 +`define uvm_unpack_intN(VAR,SIZE,PACKER=packer) \ + begin \ + bit __array[] = new [SIZE]; \ + PACKER.unpack_bits(__array, SIZE); \ + __array = new [$bits(VAR)] (__array); \ + VAR = { << bit { __array }}; \ + end + + + +// @uvm-ieee 1800.2-2017 auto B.2.5.2 +`define uvm_unpack_enumN(VAR,SIZE,TYPE,PACKER=packer) \ + begin \ + bit __array[] = new [SIZE]; \ + PACKER.unpack_bits(__array, SIZE); \ + __array = new [$bits(VAR)] (__array); \ + VAR = TYPE'({ << bit { __array }}); \ + end + + + +// @uvm-ieee 1800.2-2017 auto B.2.5.3 +`define uvm_unpack_sarrayN(VAR,SIZE,PACKER=packer) \ + begin \ + foreach (VAR `` [i]) \ + `uvm_unpack_intN(VAR``[i], SIZE, PACKER) \ + end + + + +// @uvm-ieee 1800.2-2017 auto B.2.5.4 +`define uvm_unpack_arrayN(VAR,SIZE,PACKER=packer) \ + begin \ + int sz__; \ + `uvm_unpack_intN(sz__,32,PACKER) \ + VAR = new[sz__]; \ + `uvm_unpack_sarrayN(VAR,SIZE,PACKER) \ + end + + + +// @uvm-ieee 1800.2-2017 auto B.2.5.5 +`define uvm_unpack_queueN(VAR,SIZE,PACKER=packer) \ + begin \ + int sz__; \ + `uvm_unpack_intN(sz__,32,PACKER) \ + while (VAR.size() > sz__) \ + void'(VAR.pop_back()); \ + for (int i=0; i tmp_size__) \ + void'(VAR.pop_back()); \ + for (int i = 0; i < tmp_size__; i++) \ + `uvm_unpack_real(VAR[i], PACKER) \ + end + +`endif // `ifndef UVM_PACKER_DEFINES_SVH diff --git a/test_regress/t/t_uvm/macros/uvm_phase_defines.svh b/test_regress/t/t_uvm/macros/uvm_phase_defines.svh new file mode 100644 index 0000000000..c9ece0332a --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_phase_defines.svh @@ -0,0 +1,122 @@ +`ifndef UVM_PHASE_DEFINES_SVH +`define UVM_PHASE_DEFINES_SVH +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2018 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. +//---------------------------------------------------------------------- + + +// uvm_root.svh uses these macros to simplify creation of all the phases. +// they are only to be used for UVM builtin phases, because they are simple +// delegate imps that call the corresponding methods on uvm_component. +// Also, they declare classes (uvm_XXXXX_phase) and singleton instances (XXXXX_ph) + +// If you require more complex phase functors for your custom phase, code your +// own imp class extending uvm_task/topdown/bottomup_phase base classes, following +// the pattern of the macros below, but customize the exec_task() or exec_func() +// contents to suit your enhanced functionality or derived component type/methods. +// The uvm_user_xxx_phase() macros are provided for your convenience. + + +`define m_uvm_task_phase(PHASE,COMP,PREFIX) \ + class PREFIX``PHASE``_phase extends uvm_task_phase; \ + virtual task exec_task(uvm_component comp, uvm_phase phase); \ + COMP comp_; \ + if ($cast(comp_,comp)) \ + comp_.``PHASE``_phase(phase); \ + endtask \ + local static PREFIX``PHASE``_phase m_inst; \ + `uvm_type_name_decl(`"PREFIX``PHASE``_phase`") \ + static function PREFIX``PHASE``_phase get(); \ + if(m_inst == null) begin \ + m_inst = new; \ + end \ + return m_inst; \ + endfunction \ + protected function new(string name=`"PHASE`"); \ + super.new(name); \ + endfunction \ + endclass \ + //PREFIX``PHASE``_phase PREFIX``PHASE``_ph = PREFIX``PHASE``_phase::get(); + +`define m_uvm_topdown_phase(PHASE,COMP,PREFIX) \ + class PREFIX``PHASE``_phase extends uvm_topdown_phase; \ + virtual function void exec_func(uvm_component comp, uvm_phase phase); \ + COMP comp_; \ + if ($cast(comp_,comp)) \ + comp_.``PHASE``_phase(phase); \ + endfunction \ + local static PREFIX``PHASE``_phase m_inst; \ + `uvm_type_name_decl(`"PREFIX``PHASE``_phase`") \ + static function PREFIX``PHASE``_phase get(); \ + if(m_inst == null) begin \ + m_inst = new(); \ + end \ + return m_inst; \ + endfunction \ + protected function new(string name=`"PHASE`"); \ + super.new(name); \ + endfunction \ + endclass \ + //PREFIX``PHASE``_phase PREFIX``PHASE``_ph = PREFIX``PHASE``_phase::get(); + +`define m_uvm_bottomup_phase(PHASE,COMP,PREFIX) \ + class PREFIX``PHASE``_phase extends uvm_bottomup_phase; \ + virtual function void exec_func(uvm_component comp, uvm_phase phase); \ + COMP comp_; \ + if ($cast(comp_,comp)) \ + comp_.``PHASE``_phase(phase); \ + endfunction \ + static PREFIX``PHASE``_phase m_inst; \ + `uvm_type_name_decl(`"PREFIX``PHASE``_phase`") \ + static function PREFIX``PHASE``_phase get(); \ + if(m_inst == null) begin \ + m_inst = new(); \ + end \ + return m_inst; \ + endfunction \ + protected function new(string name=`"PHASE`"); \ + super.new(name); \ + endfunction \ + endclass \ + //PREFIX``PHASE``_phase PREFIX``PHASE``_ph = PREFIX``PHASE``_phase::get(); + +`define uvm_builtin_task_phase(PHASE) \ + `m_uvm_task_phase(PHASE,uvm_component,uvm_) + +`define uvm_builtin_topdown_phase(PHASE) \ + `m_uvm_topdown_phase(PHASE,uvm_component,uvm_) + +`define uvm_builtin_bottomup_phase(PHASE) \ + `m_uvm_bottomup_phase(PHASE,uvm_component,uvm_) + + +`define uvm_user_task_phase(PHASE,COMP,PREFIX) \ + `m_uvm_task_phase(PHASE,COMP,PREFIX) + +`define uvm_user_topdown_phase(PHASE,COMP,PREFIX) \ + `m_uvm_topdown_phase(PHASE,COMP,PREFIX) + +`define uvm_user_bottomup_phase(PHASE,COMP,PREFIX) \ + `m_uvm_bottomup_phase(PHASE,COMP,PREFIX) + +`endif diff --git a/test_regress/t/t_uvm/macros/uvm_printer_defines.svh b/test_regress/t/t_uvm/macros/uvm_printer_defines.svh new file mode 100644 index 0000000000..2be896ee8c --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_printer_defines.svh @@ -0,0 +1,659 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2017-2018 Intel Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017-2018 Cisco Systems, 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// MACROS for uvm_printer usage +// +// Provides a set of printing macros that will call appropriate print methods +// inside of a uvm_printer object. All macros have two versions: one assumes +// that the name of the value is the string-ized value, whereas the other takes +// an explicit name. +// +//------------------------------------------------------------------------------ + +`ifndef UVM_PRINTER_DEFINES_SVH +`define UVM_PRINTER_DEFINES_SVH + +// uvm_print_int +// -------------- + +`define uvm_print_int(VALUE, SIZE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_int(`"VALUE`", VALUE, SIZE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_int(NAME, VALUE, SIZE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ +if (SIZE > 64) \ + PRINTER.print_field(NAME, VALUE, SIZE, RADIX, ".", `"VALUE_TYPE`"); \ +else \ + PRINTER.print_field_int(NAME, VALUE, SIZE, RADIX, ".", `"VALUE_TYPE`"); + +// uvm_print_real +// -------------- + +`define uvm_print_real(VALUE, PRINTER=printer) \ + `uvm_print_named_real(`"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_real(NAME, VALUE, PRINTER=printer) \ + PRINTER.print_real(NAME, VALUE); + +// uvm_print_enum +// -------------- + +`define uvm_print_enum(TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_enum(TYPE, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_enum(TYPE, NAME, VALUE, PRINTER=printer) \ +if (VALUE.name() == "") \ + `uvm_print_named_int(NAME, VALUE, $bits(VALUE), UVM_NORADIX, TYPE, PRINTER) \ +else \ + PRINTER.print_generic(NAME, `"TYPE`", $bits(VALUE), VALUE.name()); + +// uvm_print_object* +// ----------------- + +`define uvm_print_object(VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_object(`"VALUE`", VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_named_object(NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ +if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (RECURSION_POLICY != PRINTER.get_recursion_policy())) begin \ + uvm_recursion_policy_enum __saved_recursion_policy = PRINTER.get_recursion_policy(); \ + PRINTER.set_recursion_policy(RECURSION_POLICY); \ + `m_uvm_print_named_object(NAME, VALUE, PRINTER) \ + PRINTER.set_recursion_policy(__saved_recursion_policy); \ +end \ +else begin \ + `m_uvm_print_named_object(NAME, VALUE, PRINTER) \ +end + + +`define m_uvm_print_named_object(NAME, VALUE, PRINTER) \ +if (PRINTER.object_printed(VALUE, PRINTER.get_recursion_policy()) != uvm_policy::NEVER) begin \ + uvm_recursion_policy_enum __saved_recursion_policy = PRINTER.get_recursion_policy(); \ + PRINTER.set_recursion_policy(UVM_REFERENCE); \ + PRINTER.print_object(NAME, VALUE); \ + PRINTER.set_recursion_policy(__saved_recursion_policy); \ +end \ +else begin \ + PRINTER.print_object(NAME, VALUE); \ +end + +// uvm_print_string* +// ----------------- + +`define uvm_print_string(VALUE, PRINTER=printer) \ + `uvm_print_named_string(`"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_string(NAME, VALUE, PRINTER=printer) \ + PRINTER.print_string(NAME, VALUE); + +//////////////////////// +// Array Printing Below +//////////////////////// + +// Arrays of ints + +`define uvm_print_qda_int(ARRAY_TYPE, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(ARRAY_TYPE, `"VALUE`", VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_qda_int(ARRAY_TYPE, NAME, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ +begin \ + int __tmp_max = $right(VALUE) + 1; \ + PRINTER.print_array_header(NAME, \ + __tmp_max, \ + `"ARRAY_TYPE``(``VALUE_TYPE``)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + int __tmp_begin_elements, __tmp_end_elements; \ + __tmp_begin_elements = PRINTER.get_begin_elements(); \ + __tmp_end_elements = PRINTER.get_end_elements(); \ + /* Fast Bypass */ \ + if (__tmp_begin_elements == -1 || __tmp_end_elements == -1) begin \ + foreach (VALUE[__tmp_index]) begin \ + `uvm_print_named_int($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + $bits(VALUE[__tmp_index]), \ + RADIX, \ + VALUE_TYPE, \ + PRINTER) \ + end \ + end \ + else begin \ + int __tmp_curr; \ + foreach(VALUE[__tmp_index]) begin \ + if (__tmp_curr < __tmp_begin_elements) begin \ + `uvm_print_named_int($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + $bits(VALUE[__tmp_index]), \ + RADIX, \ + VALUE_TYPE, \ + PRINTER) \ + end \ + else \ + break; \ + __tmp_curr++; \ + end \ + if (__tmp_curr < __tmp_max ) begin \ + if ((__tmp_max - __tmp_end_elements) > __tmp_curr) \ + __tmp_curr = __tmp_max - __tmp_end_elements; \ + if (__tmp_curr < __tmp_begin_elements) \ + __tmp_curr = __tmp_begin_elements; \ + else \ + PRINTER.print_array_range(__tmp_begin_elements, __tmp_curr-1); \ + while (__tmp_curr < __tmp_max) begin \ + `uvm_print_named_int($sformatf("[%0d]", __tmp_curr), \ + VALUE[__tmp_curr], \ + $bits(VALUE[__tmp_curr]), \ + RADIX, \ + VALUE_TYPE, \ + PRINTER) \ + __tmp_curr++; \ + end \ + end \ + end \ + end \ + PRINTER.print_array_footer(__tmp_max); \ +end + +`define uvm_print_array_int(VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(da, `"VALUE`", VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_array_int(NAME, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(da, NAME, VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_sarray_int(VALUE, RADIX=UVM_RADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(sa, `"VALUE`", VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_sarray_int(NAME, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(sa, NAME, VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_queue_int(VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(queue, `"VALUE`", VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_queue_int(NAME, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_qda_int(queue, NAME, VALUE, RADIX, VALUE_TYPE, PRINTER) + +// Arrays of reals + +`define uvm_print_qda_real(ARRAY_TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_real(ARRAY_TYPE, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_qda_real(ARRAY_TYPE, NAME, VALUE, PRINTER=printer) \ +begin \ + int __tmp_max = $right(VALUE) + 1; \ + PRINTER.print_array_header(NAME, \ + __tmp_max, \ + `"ARRAY_TYPE``(real)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + int __tmp_begin_elements, __tmp_end_elements; \ + __tmp_begin_elements = PRINTER.get_begin_elements(); \ + __tmp_end_elements = PRINTER.get_end_elements(); \ + /* Fast Bypass */ \ + if (__tmp_begin_elements == -1 || __tmp_end_elements == -1) begin \ + foreach (VALUE[__tmp_index]) begin \ + `uvm_print_named_real($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + end \ + else begin \ + int __tmp_curr; \ + foreach(VALUE[__tmp_index]) begin \ + if (__tmp_curr < __tmp_begin_elements) begin \ + `uvm_print_named_real($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + else \ + break; \ + __tmp_curr++; \ + end \ + if (__tmp_curr < __tmp_max ) begin \ + if ((__tmp_max - __tmp_end_elements) > __tmp_curr) \ + __tmp_curr = __tmp_max - __tmp_end_elements; \ + if (__tmp_curr < __tmp_begin_elements) \ + __tmp_curr = __tmp_begin_elements; \ + else \ + PRINTER.print_array_range(__tmp_begin_elements, __tmp_curr-1); \ + while (__tmp_curr < __tmp_max) begin \ + `uvm_print_named_real($sformatf("[%0d]", __tmp_curr), \ + VALUE[__tmp_curr], \ + PRINTER) \ + __tmp_curr++; \ + end \ + end \ + end \ + end \ + PRINTER.print_array_footer(__tmp_max); \ +end + +`define uvm_print_array_real(VALUE, PRINTER=printer) \ + `uvm_print_named_qda_real(da, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_array_real(NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_real(da, NAME, VALUE, PRINTER) + +`define uvm_print_sarray_real(VALUE, PRINTER=printer) \ + `uvm_print_named_qda_real(sa, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_sarray_real(NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_real(sa, NAME, VALUE, PRINTER) + +`define uvm_print_queue_real(VALUE,PRINTER=printer) \ + `uvm_print_named_qda_real(queue, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_queue_real(NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_real(queue, NAME, VALUE, PRINTER) + +// Arrays of enums + +`define uvm_print_qda_enum(ARRAY_TYPE, TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(ARRAY_TYPE, TYPE, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_qda_enum(ARRAY_TYPE, TYPE, NAME, VALUE, PRINTER=printer) \ +begin \ + int __tmp_max = $right(VALUE) + 1; \ + PRINTER.print_array_header(NAME, \ + __tmp_max, \ + {`"ARRAY_TYPE``(`", `"TYPE`", ")"}); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + int __tmp_begin_elements, __tmp_end_elements; \ + __tmp_begin_elements = PRINTER.get_begin_elements(); \ + __tmp_end_elements = PRINTER.get_end_elements(); \ + /* Fast Bypass */ \ + if (__tmp_begin_elements == -1 || __tmp_end_elements == -1) begin \ + foreach (VALUE[__tmp_index]) begin \ + `uvm_print_named_enum(TYPE, \ + $sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + end \ + else begin \ + int __tmp_curr; \ + foreach(VALUE[__tmp_index]) begin \ + if (__tmp_curr < __tmp_begin_elements) begin \ + `uvm_print_named_enum(TYPE, \ + $sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + else \ + break; \ + __tmp_curr++; \ + end \ + if (__tmp_curr < __tmp_max ) begin \ + if ((__tmp_max - __tmp_end_elements) > __tmp_curr) \ + __tmp_curr = __tmp_max - __tmp_end_elements; \ + if (__tmp_curr < __tmp_begin_elements) \ + __tmp_curr = __tmp_begin_elements; \ + else \ + PRINTER.print_array_range(__tmp_begin_elements, __tmp_curr-1); \ + while (__tmp_curr < __tmp_max) begin \ + `uvm_print_named_enum(TYPE, \ + $sformatf("[%0d]", __tmp_curr), \ + VALUE[__tmp_curr], \ + PRINTER) \ + __tmp_curr++; \ + end \ + end \ + end \ + end \ + PRINTER.print_array_footer(__tmp_max); \ +end + +`define uvm_print_array_enum(TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(da, `"VALUE`", TYPE, VALUE, PRINTER) + +`define uvm_print_named_array_enum(TYPE, NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(da, TYPE, NAME, VALUE, PRINTER) + +`define uvm_print_sarray_enum(TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(sa, TYPE, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_sarray_enum(TYPE, NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(sa, TYPE, NAME, VALUE, PRINTER) + +`define uvm_print_queue_enum(TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(queue, TYPE, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_queue_enum(TYPE, NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_enum(queue, TYPE, NAME, VALUE, PRINTER) + +// Arrays of objects + +`define uvm_print_qda_object(ARRAY_TYPE, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(ARRAY_TYPE, `"VALUE`", VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_named_qda_object(ARRAY_TYPE, NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ +begin \ + int __tmp_max = $right(VALUE) + 1; \ + PRINTER.print_array_header(NAME, \ + __tmp_max, \ + `"ARRAY_TYPE``(object)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + uvm_recursion_policy_enum __tmp_recursion_policy; \ + int __tmp_begin_elements, __tmp_end_elements; \ + __tmp_begin_elements = PRINTER.get_begin_elements(); \ + __tmp_end_elements = PRINTER.get_end_elements(); \ + __tmp_recursion_policy = PRINTER.get_recursion_policy(); \ + if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (__tmp_recursion_policy != RECURSION_POLICY)) \ + PRINTER.set_recursion_policy(RECURSION_POLICY); \ + /* Fast Bypass */ \ + if (__tmp_begin_elements == -1 || __tmp_end_elements == -1) begin \ + foreach (VALUE[__tmp_index]) begin \ + `m_uvm_print_named_object($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + end \ + else begin \ + int __tmp_curr; \ + foreach(VALUE[__tmp_index]) begin \ + if (__tmp_curr < __tmp_begin_elements) begin \ + `m_uvm_print_named_object($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + else \ + break; \ + __tmp_curr++; \ + end \ + if (__tmp_curr < __tmp_max ) begin \ + if ((__tmp_max - __tmp_end_elements) > __tmp_curr) \ + __tmp_curr = __tmp_max - __tmp_end_elements; \ + if (__tmp_curr < __tmp_begin_elements) \ + __tmp_curr = __tmp_begin_elements; \ + else \ + PRINTER.print_array_range(__tmp_begin_elements, __tmp_curr-1); \ + while (__tmp_curr < __tmp_max) begin \ + `m_uvm_print_named_object($sformatf("[%0d]", __tmp_curr), \ + VALUE[__tmp_curr], \ + PRINTER) \ + __tmp_curr++; \ + end \ + end \ + end \ + if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (__tmp_recursion_policy != RECURSION_POLICY)) \ + PRINTER.set_recursion_policy(__tmp_recursion_policy); \ + end \ + PRINTER.print_array_footer(__tmp_max); \ +end + +`define uvm_print_array_object(VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(da, `"VALUE`", VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_named_array_object(NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(da, NAME, VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_sarray_object(VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(sa, `"VALUE`", VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_named_sarray_object(NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(sa, NAME, VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_queue_object(VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(queue, `"VALUE`", VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_named_queue_object(NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_qda_object(queue, NAME, VALUE, RECURSION_POLICY, PRINTER) + +// Arrays of strings + +`define uvm_print_qda_string(ARRAY_TYPE, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(ARRAY_TYPE, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_qda_string(ARRAY_TYPE, NAME, VALUE, PRINTER=printer) \ +begin \ + int __tmp_max = $right(VALUE) + 1; \ + PRINTER.print_array_header(NAME, \ + __tmp_max, \ + `"ARRAY_TYPE``(string)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + int __tmp_begin_elements, __tmp_end_elements; \ + __tmp_begin_elements = PRINTER.get_begin_elements(); \ + __tmp_end_elements = PRINTER.get_end_elements(); \ + /* Fast Bypass */ \ + if (__tmp_begin_elements == -1 || __tmp_end_elements == -1) begin \ + foreach (VALUE[__tmp_index]) begin \ + `uvm_print_named_string($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + end \ + else begin \ + int __tmp_curr; \ + foreach(VALUE[__tmp_index]) begin \ + if (__tmp_curr < __tmp_begin_elements) begin \ + `uvm_print_named_string($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER) \ + end \ + else \ + break; \ + __tmp_curr++; \ + end \ + if (__tmp_curr < __tmp_max ) begin \ + if ((__tmp_max - __tmp_end_elements) > __tmp_curr) \ + __tmp_curr = __tmp_max - __tmp_end_elements; \ + if (__tmp_curr < __tmp_begin_elements) \ + __tmp_curr = __tmp_begin_elements; \ + else \ + PRINTER.print_array_range(__tmp_begin_elements, __tmp_curr-1); \ + while (__tmp_curr < __tmp_max) begin \ + `uvm_print_named_string($sformatf("[%0d]", __tmp_curr), \ + VALUE[__tmp_curr], \ + PRINTER) \ + __tmp_curr++; \ + end \ + end \ + end \ + end \ + PRINTER.print_array_footer(__tmp_max); \ +end + +`define uvm_print_array_string(VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(da, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_array_string(NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(da, NAME, VALUE, PRINTER) + +`define uvm_print_sarray_string(VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(sa, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_sarray_string(NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(sa, NAME, VALUE, PRINTER) + +`define uvm_print_queue_string(VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(queue, `"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_queue_string(NAME, VALUE, PRINTER=printer) \ + `uvm_print_named_qda_string(queue, NAME, VALUE, PRINTER) + +//----------------------------------------------------------------------------- +// +// Associative array printing methods +// +//----------------------------------------------------------------------------- + +`define uvm_print_aa_int_string(VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ + `uvm_print_named_aa_int_string(`"VALUE`", VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_aa_int_string(NAME, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=integral, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + `"aa(``VALUE_TYPE``,string)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + foreach(VALUE[__tmp_index]) \ + `uvm_print_named_int($sformatf("[%s]", __tmp_index), \ + VALUE[__tmp_index], \ + $bits(VALUE[__tmp_index]), \ + RADIX, \ + VALUE_TYPE, \ + PRINTER ) \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + +`define uvm_print_aa_object_string(VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ + `uvm_print_named_aa_object_string(`"VALUE`", VALUE, RECURSION_POLICY, PRINTER) + +`define uvm_print_named_aa_object_string(NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + "aa(object,string)"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + uvm_recursion_policy_enum __tmp_recursion_policy; \ + __tmp_recursion_policy = PRINTER.get_recursion_policy(); \ + if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (__tmp_recursion_policy != RECURSION_POLICY)) \ + PRINTER.set_recursion_policy(RECURSION_POLICY); \ + foreach(VALUE[__tmp_index]) \ + `m_uvm_print_named_object($sformatf("[%s]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER ) \ + if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (__tmp_recursion_policy != RECURSION_POLICY)) \ + PRINTER.set_recursion_policy(__tmp_recursion_policy); \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + +`define uvm_print_aa_string_string(VALUE, PRINTER=printer) \ + `uvm_print_named_aa_string_string(`"VALUE`", VALUE, PRINTER) + +`define uvm_print_named_aa_string_string(NAME, VALUE, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + "aa(string,string)"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + foreach(VALUE[__tmp_index]) \ + `uvm_print_named_string($sformatf("[%s]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER ) \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + +`define uvm_print_aa_int_int(VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=int, INDEX_TYPE=int, PRINTER=printer) \ + `uvm_print_named_aa_int_int(`"VALUE`", VALUE, RADIX, VALUE_TYPE, INDEX_TYPE, PRINTER) + +`define uvm_print_named_aa_int_int(NAME, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=int, INDEX_TYPE=int, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + `"aa(``VALUE_TYPE``,``INDEX_TYPE``)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + foreach(VALUE[__tmp_index]) \ + `uvm_print_named_int($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + $bits(VALUE[__tmp_index]), \ + RADIX, \ + VALUE_TYPE, \ + PRINTER ) \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + +`define uvm_print_aa_object_int(VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, INDEX_TYPE=int, PRINTER=printer) \ + `uvm_print_named_aa_object_int(`"VALUE`", VALUE, RECURSION_POLICY, INDEX_TYPE, PRINTER) + +`define uvm_print_named_aa_object_int(NAME, VALUE, RECURSION_POLICY=UVM_DEFAULT_POLICY, INDEX_TYPE=int, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + `"aa(object,``INDEX_TYPE``)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + uvm_recursion_policy_enum __tmp_recursion_policy; \ + __tmp_recursion_policy = PRINTER.get_recursion_policy(); \ + if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (__tmp_recursion_policy != RECURSION_POLICY)) \ + PRINTER.set_recursion_policy(RECURSION_POLICY); \ + foreach(VALUE[__tmp_index]) \ + `m_uvm_print_named_object($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER ) \ + if ((RECURSION_POLICY != UVM_DEFAULT_POLICY) && \ + (__tmp_recursion_policy != RECURSION_POLICY)) \ + PRINTER.set_recursion_policy(__tmp_recursion_policy); \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + +`define uvm_print_aa_string_int(VALUE, INDEX_TYPE=int, PRINTER=printer) \ + `uvm_print_named_aa_string_int(`"VALUE`", VALUE, INDEX_TYPE, PRINTER) + +`define uvm_print_named_aa_string_int(NAME, VALUE, INDEX_TYPE=int, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + `"aa(string,``INDEX_TYPE``)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + foreach(VALUE[__tmp_index]) \ + `uvm_print_named_string($sformatf("[%0d]", __tmp_index), \ + VALUE[__tmp_index], \ + PRINTER ) \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + +`define uvm_print_aa_int_enum(ENUM_TYPE, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=int, PRINTER=printer) \ + `uvm_print_named_aa_int_enum(`"VALUE`", ENUM_TYPE, VALUE, RADIX, VALUE_TYPE, PRINTER) + +`define uvm_print_named_aa_int_enum(NAME, ENUM_TYPE, VALUE, RADIX=UVM_NORADIX, VALUE_TYPE=int, PRINTER=printer) \ +begin \ + PRINTER.print_array_header(NAME, \ + VALUE.num(), \ + `"aa(``VALUE_TYPE``,``ENUM_TYPE``)`"); \ + if ((PRINTER.get_max_depth() == -1) || \ + (PRINTER.get_active_object_depth() < PRINTER.get_max_depth()+1)) begin \ + foreach(VALUE[__tmp_index]) \ + `uvm_print_named_int((__tmp_index.name() == "") ? $sformatf("[%s'(%0d)]", `"ENUM_TYPE`",__tmp_index) \ + : $sformatf("[%s]", __tmp_index.name()), \ + VALUE[__tmp_index], \ + $bits(VALUE[__tmp_index]), \ + RADIX, \ + VALUE_TYPE, \ + PRINTER ) \ + end \ + PRINTER.print_array_footer(VALUE.num()); \ +end + + +`endif // `ifndef UVM_PRINTER_DEFINES_SVH + diff --git a/test_regress/t/t_uvm/macros/uvm_recorder_defines.svh b/test_regress/t/t_uvm/macros/uvm_recorder_defines.svh new file mode 100644 index 0000000000..11a93bfea2 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_recorder_defines.svh @@ -0,0 +1,345 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2009 Mentor Graphics Corporation +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2018 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Group -- NODOCS -- Recording Macros +// +// The recording macros assist users who implement the +// method. They help ensure that the fields are recorded using a vendor- +// independent API. Unlike the policy, fields recorded using +// the macros do not lose type information--they are passed +// directly to the vendor-specific API. This results in more efficient recording +// and no artificial limit on bit-widths. See your simulator vendor's +// documentation for more information on its transaction recording capabilities. +//------------------------------------------------------------------------------ + +`ifndef UVM_RECORDER_DEFINES_SVH +`define UVM_RECORDER_DEFINES_SVH + +// Group: Recording Macros +// +// The recording macros are implemented as described in section B.2.3 of the +// 1800.2 specification. +// +// The Accellera implementation adds an additional ~RECORDER~ argument to +// these macros with a default value of 'recorder'. This allows the macros +// to be used in environments with alternative recorder names. +// +// For example, <`uvm_record_string> is defined in the LRM as +// | `define uvm_record_string(NAME,VALUE) +// +// Whereas the implementation is +// | `define uvm_record_string(NAME,VALUE,RECORDER=recorder) +// +// This allows for usage such as +// | function void record_foo( uvm_packer other_recorder ); +// | `uvm_record_string("foo", foo, other_recorder) +// | endfunction : record_foo +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 + + +// Macro -- NODOCS -- `uvm_record_attribute +// +// Vendor-independent macro to hide tool-specific interface for +// recording attributes (fields) to a transaction database. +// +//| `uvm_record_attribute(TR_HANDLE, NAME, VALUE) +// +// The default implementation of the macro passes ~NAME~ and +// ~VALUE~ through to the method. +// +// This macro should not be called directly by the user, the +// other recording macros will call it automatically if +// returns true. +// + +`ifndef uvm_record_attribute + `ifdef QUESTA + `define uvm_record_attribute(TR_HANDLE,NAME,VALUE,RECORDER=recorder) \ + $add_attribute(TR_HANDLE,VALUE,NAME); + `else + // @uvm-ieee 1800.2-2017 auto B.2.3.1 + `define uvm_record_attribute(TR_HANDLE,NAME,VALUE,RECORDER=recorder) \ + RECORDER.record_generic(NAME, $sformatf("%p", VALUE)); + `endif +`endif + +// Macro -- NODOCS -- `uvm_record_int +// +//| `uvm_record_int(NAME,VALUE,SIZE[,RADIX]) +// +// The ~`uvm_record_int~ macro takes the same arguments as +// the method (including the optional ~RADIX~). +// +// The default implementation will pass the name/value pair to +// <`uvm_record_attribute> if enabled, otherwise the information +// will be passed to . +// + +`ifndef uvm_record_int + // @uvm-ieee 1800.2-2017 auto B.2.3.2 + `define uvm_record_int(NAME,VALUE,SIZE,RADIX = UVM_NORADIX,RECORDER=recorder) \ + if (RECORDER != null && RECORDER.is_open()) begin \ + if (RECORDER.use_record_attribute()) \ + `uvm_record_attribute(RECORDER.get_record_attribute_handle(),NAME,VALUE,RECORDER) \ + else \ + if (SIZE > 64) \ + RECORDER.record_field(NAME, VALUE, SIZE, RADIX); \ + else \ + RECORDER.record_field_int(NAME, VALUE, SIZE, RADIX); \ + end +`endif + +// Macro -- NODOCS -- `uvm_record_string +// +//| `uvm_record_string(NAME,VALUE) +// +// The ~`uvm_record_string~ macro takes the same arguments as +// the method. +// +// The default implementation will pass the name/value pair to +// <`uvm_record_attribute> if enabled, otherwise the information +// will be passed to . +// + +`ifndef uvm_record_string + // @uvm-ieee 1800.2-2017 auto B.2.3.3 + `define uvm_record_string(NAME,VALUE,RECORDER=recorder) \ + if (RECORDER != null && RECORDER.is_open()) begin \ + if (RECORDER.use_record_attribute()) \ + `uvm_record_attribute(RECORDER.get_record_attribute_handle(),NAME,VALUE,RECORDER) \ + else \ + RECORDER.record_string(NAME,VALUE); \ + end +`endif + +// Macro -- NODOCS -- `uvm_record_time +// +//| `uvm_record_time(NAME,VALUE) +// +// The ~`uvm_record_time~ macro takes the same arguments as +// the method. +// +// The default implementation will pass the name/value pair to +// <`uvm_record_attribute> if enabled, otherwise the information +// will be passed to . +// +`ifndef uvm_record_time + // @uvm-ieee 1800.2-2017 auto B.2.3.4 + `define uvm_record_time(NAME,VALUE,RECORDER=recorder) \ + if (RECORDER != null && RECORDER.is_open()) begin \ + if (RECORDER.use_record_attribute()) \ + `uvm_record_attribute(RECORDER.get_record_attribute_handle(),NAME,VALUE,RECORDER) \ + else \ + RECORDER.record_time(NAME,VALUE); \ + end +`endif + + +// Macro -- NODOCS -- `uvm_record_real +// +//| `uvm_record_real(NAME,VALUE) +// +// The ~`uvm_record_real~ macro takes the same arguments as +// the method. +// +// The default implementation will pass the name/value pair to +// <`uvm_record_attribute> if enabled, otherwise the information +// will be passed to . +// +`ifndef uvm_record_real + // @uvm-ieee 1800.2-2017 auto B.2.3.5 + `define uvm_record_real(NAME,VALUE,RECORDER=recorder) \ + if (RECORDER != null && RECORDER.is_open()) begin \ + if (RECORDER.use_record_attribute()) \ + `uvm_record_attribute(RECORDER.get_record_attribute_handle(),NAME,VALUE,RECORDER) \ + else \ + RECORDER.record_field_real(NAME,VALUE); \ + end +`endif + +// @uvm-ieee 1800.2-2017 auto B.2.3.6 +`define uvm_record_field(NAME,VALUE,RECORDER=recorder) \ + if (RECORDER != null && RECORDER.is_open()) begin \ + if (RECORDER.use_record_attribute()) begin \ + `uvm_record_attribute(RECORDER.get_record_attribute_handle(),NAME,VALUE,RECORDER) \ + end \ + else \ + RECORDER.record_generic(NAME, $sformatf("%p", VALUE)); \ + end + +`define uvm_record_enum(NAME,VALUE,TYPE,RECORDER=recorder) \ + if (RECORDER != null && RECORDER.is_open()) begin \ + if (RECORDER.use_record_attribute()) begin \ + `uvm_record_attribute(RECORDER.get_record_attribute_handle(),NAME,VALUE,RECORDER) \ + end \ + else begin \ + if (VALUE.name() == "") \ + RECORDER.record_generic(NAME, $sformatf("%0d", VALUE), `"TYPE`"); \ + else \ + RECORDER.record_generic(NAME, VALUE.name(), `"TYPE`"); \ + end \ + end + +// uvm_record_qda_int +// ------------------ + +`define uvm_record_qda_int(ARG, RADIX,RECORDER=recorder) \ + begin \ + int sz__ = $size(ARG); \ + if(sz__ == 0) begin \ + `uvm_record_int(`"ARG`", 0, 32, UVM_DEC,RECORDER) \ + end \ + else if(sz__ < 10) begin \ + foreach(ARG[i]) begin \ + string nm__ = $sformatf("%s[%0d]", `"ARG`", i); \ + `uvm_record_int(nm__, ARG[i], $bits(ARG[i]), RADIX, RECORDER) \ + end \ + end \ + else begin \ + for(int i=0; i<5; ++i) begin \ + string nm__ = $sformatf("%s[%0d]", `"ARG`", i); \ + `uvm_record_int(nm__, ARG[i], $bits(ARG[i]), RADIX, RECORDER) \ + end \ + for(int i=sz__-5; i type. +// +`ifndef UVM_REG_ADDR_WIDTH + // @uvm-ieee 1800.2-2017 auto B.6.4 + `define UVM_REG_ADDR_WIDTH 64 +`endif + + +// Macro -- NODOCS -- `UVM_REG_DATA_WIDTH +// +// Maximum data width in bits +// +// Default value is 64. Used to define the type. +// +`ifndef UVM_REG_DATA_WIDTH + // @uvm-ieee 1800.2-2017 auto B.6.5 + `define UVM_REG_DATA_WIDTH 64 +`endif + + +// Macro -- NODOCS -- `UVM_REG_BYTENABLE_WIDTH +// +// Maximum number of byte enable bits +// +// Default value is one per byte in <`UVM_REG_DATA_WIDTH>. +// Used to define the type. +// +`ifndef UVM_REG_BYTENABLE_WIDTH + `define UVM_REG_BYTENABLE_WIDTH ((`UVM_REG_DATA_WIDTH-1)/8+1) +`endif + + +// Macro -- NODOCS -- `UVM_REG_CVR_WIDTH +// +// Maximum number of bits in a coverage model set. +// +// Default value is 32. +// +`ifndef UVM_REG_CVR_WIDTH + // @uvm-ieee 1800.2-2017 auto B.6.7 + `define UVM_REG_CVR_WIDTH 32 +`endif diff --git a/test_regress/t/t_uvm/macros/uvm_resource_defines.svh b/test_regress/t/t_uvm/macros/uvm_resource_defines.svh new file mode 100644 index 0000000000..04d71a8195 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_resource_defines.svh @@ -0,0 +1,166 @@ +//---------------------------------------------------------------------- +// Copyright 2018 Cadence Design Systems, Inc. +// Copyright 2018 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// +// MACROS for resource usage +// +// Provides a set of macros which are useful for interacting with the +// resource database. +// +//------------------------------------------------------------------------------ + +`ifndef UVM_RESOURCE_DEFINES_SVH +`define UVM_RESOURCE_DEFINES_SVH + +// m_uvm_resource_read +// ------------------- +// Casts ~RSRC~ to uvm_resource#(TYPE) and if successful +// reads the resource into ~VAL~ with accessor ~OBJ~. +// +// ~SUCCESS~ shall be set to true if the resource was succesfully +// read, false otherwise. + +`define uvm_resource_read(SUCCESS, RSRC, TYPE, VAL, OBJ=null) \ +begin \ + uvm_resource#(TYPE) __tmp_rsrc__; \ + SUCCESS = $cast(__tmp_rsrc__, RSRC); \ + if (SUCCESS) begin \ + VAL = __tmp_rsrc__.read(OBJ); \ + end \ +end + +// uvm_resource_builtin_int_read +// ----------------------------- +// Attempts to read an integral typed resource ~RSRC~ +// into VAL. +// +// ~SUCCESS~ shall be set to true if the resource was succesfully +// read, false otherwise. +// +// Supported Types: +// - uvm_integral_t +// - uvm_bitstream_t +// - int +// - int unsigned +// + +`define uvm_resource_builtin_int_read(SUCCESS, RSRC, VAL, OBJ=null) \ +begin \ + `uvm_resource_read(SUCCESS, RSRC, uvm_integral_t, VAL, OBJ) \ + if (!SUCCESS) \ + `uvm_resource_read(SUCCESS, RSRC, uvm_bitstream_t, VAL, OBJ) \ + if (!SUCCESS) \ + `uvm_resource_read(SUCCESS, RSRC, int, VAL, OBJ) \ + if (!SUCCESS) \ + `uvm_resource_read(SUCCESS, RSRC, int unsigned, VAL, OBJ) \ +end + +// uvm_resource_int_read +// --------------------- +// Attempts to read an integral typed resource ~RSRC~, +// starting with ~TYPE~ before checking the builtin types. +// +// ~SUCCESS~ shall be set to true if the resource was succesfully +// read, false otherwise. +// + +`define uvm_resource_int_read(SUCCESS, RSRC, TYPE, VAL, OBJ=null) \ +begin \ + `uvm_resource_read(SUCCESS, RSRC, TYPE, VAL, OBJ) \ + if (!SUCCESS) \ + `uvm_resource_builtin_int_read(SUCCESS, RSRC, VAL, OBJ) \ +end + +// uvm_resource_enum_read +// --------------------- +// Attempts to read an integral typed resource ~RSRC~, +// starting with ~TYPE~ and string before checking the +// builtin intergral types. +// +// ~SUCCESS~ shall be set to true if the resource was succesfully +// read, false otherwise. +// + +`define uvm_resource_enum_read(SUCCESS, RSRC, TYPE, VAL, OBJ=null) \ +begin \ + `uvm_resource_read(SUCCESS, RSRC, TYPE, VAL, OBJ) \ + if (!SUCCESS) begin \ + TYPE __tmp_val__; \ + string __tmp_string_val__; \ + bit __tmp_success_val__; \ + `uvm_resource_read(__tmp_success_val__, \ + RSRC, \ + string, \ + __tmp_string_val__, \ + OBJ) \ + if (__tmp_success_val__ && \ + uvm_enum_wrapper#(TYPE)::from_name(__tmp_string_val__, \ + __tmp_val__)) begin \ + VAL = __tmp_val__; \ + SUCCESS = __tmp_success_val__; \ + end \ + end \ + if (!SUCCESS) begin \ + typedef bit [$bits(TYPE)-1:0] __tmp_int_t__; \ + __tmp_int_t__ __tmp_int_val__; \ + bit __tmp_success_val__; \ + `uvm_resource_int_read(__tmp_success_val__, \ + RSRC, \ + __tmp_int_t__, \ + __tmp_int_val__, \ + OBJ) \ + if (__tmp_success_val__) begin \ + VAL = TYPE'(__tmp_int_val__); \ + SUCCESS = __tmp_success_val__; \ + end \ + end \ +end + +// uvm_resource_real_read +// --------------------- +// Attempts to read a real typed resource ~RSRC~, +// starting with 'real' before checking the +// builtin intergral types. +// +// ~SUCCESS~ shall be set to true if the resource was succesfully +// read, false otherwise. +// + +`define uvm_resource_real_read(SUCCESS, RSRC, VAL, OBJ=null) \ +begin \ + `uvm_resource_read(SUCCESS, RSRC, real, VAL, OBJ) \ + if (!SUCCESS) begin \ + typedef bit [63:0] __tmp_int_t__; \ + __tmp_int_t__ __tmp_int_val__; \ + bit __tmp_success_val__; \ + `uvm_resource_int_read(__tmp_success_val__, \ + RSRC, \ + __tmp_int_t__, \ + __tmp_int_val__, \ + OBJ) \ + if (__tmp_success_val__) begin \ + VAL = $bitstoreal(__tmp_int_val__); \ + SUCCESS = __tmp_success_val__; \ + end \ + end \ +end + +`endif // `ifndef UVM_RESOURCE_DEFINES_SVH diff --git a/test_regress/t/t_uvm/macros/uvm_sequence_defines.svh b/test_regress/t/t_uvm/macros/uvm_sequence_defines.svh new file mode 100644 index 0000000000..c8651d8db9 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_sequence_defines.svh @@ -0,0 +1,312 @@ +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2018 AMD +// Copyright 2014-2018 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. +//------------------------------------------------------------------------------ + +// Title -- NODOCS -- Sequence-Related Macros + + + +//----------------------------------------------------------------------------- +// +// Group -- NODOCS -- Sequence on Sequencer Action Macros +// +// These macros are used to start sequences and sequence items on a specific +// sequencer. The sequence or item is created and executed on the given +// sequencer. +//----------------------------------------------------------------------------- + + +// MACRO -- NODOCS -- `uvm_create +// +//| `uvm_create(SEQ_OR_ITEM, SEQR=get_sequencer()) +// +// This action creates the item or sequence using the factory. It also sets the +// parent sequence to the sequence in which the macro is invoked, +// and it sets the sequencer to the specified ~SEQR~ argument. +// It intentionally does zero processing. After this action completes, +// the user can manually set values, manipulate rand_mode and constraint_mode, etc. + +// @uvm-ieee 1800.2-2017 auto B.3.1.1 +`define uvm_create(SEQ_OR_ITEM, SEQR=get_sequencer()) \ + begin \ + uvm_object_wrapper w_; \ + w_ = SEQ_OR_ITEM.get_type(); \ + $cast(SEQ_OR_ITEM , create_item(w_, SEQR, `"SEQ_OR_ITEM`"));\ + end + + +// MACRO -- NODOCS -- `uvm_do +// +//| `uvm_do(SEQ_OR_ITEM, SEQR=get_sequencer(), PRIORITY=-1, CONSTRAINTS={}) +// +// This macro takes as an argument a uvm_sequence_item variable or object. +// The argument is created using <`uvm_create>, which sets the sequencer to +// the specified ~SEQR~ argument. +// In the case of an item, it is randomized after the call to +// returns. +// This is called late-randomization. +// In the case of a sequence, the sub-sequence is started using +// with ~call_pre_post~ set to 0. +// In the case of an item, +// the item is sent to the driver through the associated sequencer. +// +// For a sequence item, the following are called, in order +// +//| +//| `uvm_create(item) +//| sequencer.wait_for_grant(prior) (task) +//| this.pre_do(1) (task) +//| item.randomize() +//| this.mid_do(item) (func) +//| sequencer.send_request(item) (func) +//| sequencer.wait_for_item_done() (task) +//| this.post_do(item) (func) +//| +// +// For a sequence, the following are called, in order +// +//| +//| `uvm_create(sub_seq) +//| sub_seq.randomize() +//| sub_seq.pre_start() (task) +//| this.pre_do(0) (task) +//| this.mid_do(sub_seq) (func) +//| sub_seq.body() (task) +//| this.post_do(sub_seq) (func) +//| sub_seq.post_start() (task) +//| + +// @uvm-ieee 1800.2-2017 auto B.3.1.4 +`define uvm_do(SEQ_OR_ITEM, SEQR=get_sequencer(), PRIORITY=-1, CONSTRAINTS={}) \ + begin \ + `uvm_create(SEQ_OR_ITEM, SEQR) \ + `uvm_rand_send(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS) \ + end + + +//----------------------------------------------------------------------------- +// +// Group -- NODOCS -- Sequence Action Macros for Pre-Existing Sequences +// +// These macros are used to start sequences and sequence items that do not +// need to be created. +//----------------------------------------------------------------------------- + + +// MACRO -- NODOCS -- `uvm_send +// +//| `uvm_send(SEQ_OR_ITEM, PRIORITY=-1) +// +// This macro processes the item or sequence that has been created using +// `uvm_create. The processing is done without randomization. Essentially, an +// `uvm_do without the create or randomization. + +// @uvm-ieee 1800.2-2017 auto B.3.1.2 +`define uvm_send(SEQ_OR_ITEM, PRIORITY=-1) \ + begin \ + uvm_sequence_base __seq; \ + if (!$cast(__seq,SEQ_OR_ITEM)) begin \ + start_item(SEQ_OR_ITEM, PRIORITY);\ + finish_item(SEQ_OR_ITEM, PRIORITY);\ + end \ + else __seq.start(__seq.get_sequencer(), this, PRIORITY, 0);\ + end + + +// MACRO -- NODOCS -- `uvm_rand_send +// +//| `uvm_rand_send(SEQ_OR_ITEM, PRIORITY=-1, CONSTRAINTS={}) +// +// This macro processes the item or sequence that has been already been +// allocated (with `uvm_create). The processing is done with +// randomization. + +// @uvm-ieee 1800.2-2017 auto B.3.1.3 +`define uvm_rand_send(SEQ_OR_ITEM, PRIORITY=-1, CONSTRAINTS={}) \ + begin \ + uvm_sequence_base __seq; \ + if ( SEQ_OR_ITEM.is_item() ) begin \ + start_item(SEQ_OR_ITEM, PRIORITY);\ + if ( ! SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \ + `uvm_warning("RNDFLD", "Randomization failed in uvm_rand_send action") \ + end\ + finish_item(SEQ_OR_ITEM, PRIORITY);\ + end \ + else if ( $cast( __seq, SEQ_OR_ITEM ) ) begin \ + __seq.set_item_context(this,SEQ_OR_ITEM.get_sequencer()); \ + if ( __seq.get_randomize_enabled() ) begin \ + if ( ! SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \ + `uvm_warning("RNDFLD", "Randomization failed in uvm_rand_send action") \ + end \ + end \ + __seq.start(__seq.get_sequencer(), this, PRIORITY, 0);\ + end \ + else begin \ + `uvm_warning("NOT_SEQ_OR_ITEM", "Object passed uvm_rand_send appears to be neither a sequence or item." ) \ + end \ + end + + + + +//----------------------------------------------------------------------------- +// +// Group- Sequence Library +// +//----------------------------------------------------------------------------- + + +// MACRO -- NODOCS -- `uvm_add_to_sequence_library +// +// Adds the given sequence ~TYPE~ to the given sequence library ~LIBTYPE~ +// +//| `uvm_add_to_seq_lib(TYPE,LIBTYPE) +// +// Invoke any number of times within a sequence declaration to statically add +// that sequence to one or more sequence library types. The sequence will then +// be available for selection and execution in all instances of the given +// sequencer types. +// +//| class seqA extends uvm_sequence_base #(simple_item); +//| +//| function new(string name=`"TYPE`"); +//| super.new(name); +//| endfunction +//| +//| `uvm_object_utils(seqA) +//| +//| `uvm_add_to_seq_lib(seqA, simple_seq_lib_RST) +//| `uvm_add_to_seq_lib(seqA, simple_seq_lib_CFG) +//| +//| virtual task body(); \ +//| `uvm_info("SEQ_START", {"Executing sequence '", get_full_name(), +//| "' (",get_type_name(),")"},UVM_HIGH) +//| #10; +//| endtask +//| +//| endclass + + +// @uvm-ieee 1800.2-2017 auto B.3.2.1 +`define uvm_add_to_seq_lib(TYPE,LIBTYPE) \ + static bit add_``TYPE``_to_seq_lib_``LIBTYPE =\ + LIBTYPE::m_add_typewide_sequence(TYPE::get_type()); + + + +// MACRO -- NODOCS -- `uvm_sequence_library_utils +// +//| `uvm_sequence_library_utils(TYPE) +// +// Declares the infrastructure needed to define extensions to the +// class. You define new sequence library subtypes +// to statically specify sequence membership from within sequence +// definitions. See also <`uvm_add_to_sequence_library> for more information. +// +// +//| typedef simple_seq_lib uvm_sequence_library #(simple_item); +//| +//| class simple_seq_lib_RST extends simple_seq_lib; +//| +//| `uvm_object_utils(simple_seq_lib_RST) +//| +//| `uvm_sequence_library_utils(simple_seq_lib_RST) +//| +//| function new(string name=""); +//| super.new(name); +//| endfunction +//| +//| endclass +// +// Each library, itself a sequence, can then be started independently +// on different sequencers or in different phases of the same sequencer. +// See for information on +// starting default sequences. + +// @uvm-ieee 1800.2-2017 auto 14.4.2 +// @uvm-ieee 1800.2-2017 auto B.3.2.2 +`define uvm_sequence_library_utils(TYPE) \ +\ + static protected uvm_object_wrapper m_typewide_sequences[$]; \ + \ + function void init_sequence_library(); \ + foreach (TYPE::m_typewide_sequences[i]) \ + sequences.push_back(TYPE::m_typewide_sequences[i]); \ + endfunction \ + \ + static function void add_typewide_sequence(uvm_object_wrapper seq_type); \ + if (m_static_check(seq_type)) \ + TYPE::m_typewide_sequences.push_back(seq_type); \ + endfunction \ + \ + static function void add_typewide_sequences(uvm_object_wrapper seq_types[$]); \ + foreach (seq_types[i]) \ + TYPE::add_typewide_sequence(seq_types[i]); \ + endfunction \ + \ + static function bit m_add_typewide_sequence(uvm_object_wrapper seq_type); \ + TYPE::add_typewide_sequence(seq_type); \ + return 1; \ + endfunction + + + +//----------------------------------------------------------------------------- +// +// Group -- NODOCS -- Sequencer Subtypes +// +//----------------------------------------------------------------------------- + + +// MACRO -- NODOCS -- `uvm_declare_p_sequencer +// +// This macro is used to declare a variable ~p_sequencer~ whose type is +// specified by ~SEQUENCER~. +// +//| `uvm_declare_p_sequencer(SEQUENCER) +// +// The example below shows using the `uvm_declare_p_sequencer macro +// along with the uvm_object_utils macros to set up the sequence but +// not register the sequence in the sequencer's library. +// +//| class mysequence extends uvm_sequence#(mydata); +//| `uvm_object_utils(mysequence) +//| `uvm_declare_p_sequencer(some_seqr_type) +//| task body; +//| //Access some variable in the user's custom sequencer +//| if(p_sequencer.some_variable) begin +//| ... +//| end +//| endtask +//| endclass +// + +// @uvm-ieee 1800.2-2017 auto B.3.3 +`define uvm_declare_p_sequencer(SEQUENCER) \ + SEQUENCER p_sequencer;\ + virtual function void m_set_p_sequencer();\ + super.m_set_p_sequencer(); \ + if( !$cast(p_sequencer, m_sequencer)) \ + `uvm_fatal("DCLPSQ", \ + $sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name())) \ + endfunction diff --git a/test_regress/t/t_uvm/macros/uvm_tlm_defines.svh b/test_regress/t/t_uvm/macros/uvm_tlm_defines.svh new file mode 100644 index 0000000000..c1c747df13 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_tlm_defines.svh @@ -0,0 +1,642 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Intel Corporation +// Copyright 2013-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2015-2018 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. +//---------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// Title -- NODOCS -- UVM TLM Implementation Port Declaration Macros +// +// The UVM TLM implementation declaration macros provide a way for components +// to provide multiple implementation ports of the same implementation +// interface. When an implementation port is defined using the built-in +// set of imps, there must be exactly one implementation of the interface. +// +// For example, if a component needs to provide a put implementation then +// it would have an implementation port defined like: +// +//| class mycomp extends uvm_component; +//| uvm_put_imp#(data_type, mycomp) put_imp; +//| ... +//| virtual task put (data_type t); +//| ... +//| endtask +//| endclass +// +// There are times, however, when you need more than one implementation +// for an interface. This set of declarations allow you to easily create +// a new implementation class to allow for multiple implementations. Although +// the new implementation class is a different class, it can be bound to +// the same types of exports and ports as the original class. Extending +// the put example above, let's say that mycomp needs to provide two put +// implementation ports. In that case, you would do something like: +// +//| //Define two new put interfaces which are compatible with uvm_put_ports +//| //and uvm_put_exports. +//| +//| `uvm_put_imp_decl(_1) +//| `uvm_put_imp_decl(_2) +//| +//| class my_put_imp#(type T=int) extends uvm_component; +//| uvm_put_imp_1#(T,my_put_imp#(T)) put_imp1; +//| uvm_put_imp_2#(T,my_put_imp#(T)) put_imp2; +//| ... +//| function void put_1 (input T t); +//| //puts coming into put_imp1 +//| ... +//| endfunction +//| function void put_2(input T t); +//| //puts coming into put_imp2 +//| ... +//| endfunction +//| endclass +// +// The important thing to note is that each `uvm__imp_decl creates a +// new class of type uvm__imp, where suffix is the input +// argument to the macro. For this reason, you will typically want to put +// these macros in a separate package to avoid collisions and to allow +// sharing of the definitions. +//----------------------------------------------------------------------------- + +// MACRO -- NODOCS -- `uvm_blocking_put_imp_decl +// +//| `uvm_blocking_put_imp_decl(SFX) +// +// Define the class uvm_blocking_put_impSFX for providing blocking put +// implementations. ~SFX~ is the suffix for the new class type. + +// @uvm-ieee 1800.2-2017 auto B.5.1 +`define uvm_blocking_put_imp_decl(SFX) \ +class uvm_blocking_put_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,`"uvm_blocking_put_imp``SFX`",IMP) \ + `UVM_BLOCKING_PUT_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_put_imp_decl +// +//| `uvm_nonblocking_put_imp_decl(SFX) +// +// Define the class uvm_nonblocking_put_impSFX for providing non-blocking +// put implementations. ~SFX~ is the suffix for the new class type. + +// @uvm-ieee 1800.2-2017 auto B.5.2 +`define uvm_nonblocking_put_imp_decl(SFX) \ +class uvm_nonblocking_put_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_PUT_MASK,`"uvm_nonblocking_put_imp``SFX`",IMP) \ + `UVM_NONBLOCKING_PUT_IMP_SFX( SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_put_imp_decl +// +//| `uvm_put_imp_decl(SFX) +// +// Define the class uvm_put_impSFX for providing both blocking and +// non-blocking put implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.3 +`define uvm_put_imp_decl(SFX) \ +class uvm_put_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_PUT_MASK,`"uvm_put_imp``SFX`",IMP) \ + `UVM_BLOCKING_PUT_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_NONBLOCKING_PUT_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_blocking_get_imp_decl +// +//| `uvm_blocking_get_imp_decl(SFX) +// +// Define the class uvm_blocking_get_impSFX for providing blocking get +// implementations. ~SFX~ is the suffix for the new class type. + +// @uvm-ieee 1800.2-2017 auto B.5.4 +`define uvm_blocking_get_imp_decl(SFX) \ +class uvm_blocking_get_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_GET_MASK,`"uvm_blocking_get_imp``SFX`",IMP) \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_get_imp_decl +// +//| `uvm_nonblocking_get_imp_decl(SFX) +// +// Define the class uvm_nonblocking_get_impSFX for providing non-blocking +// get implementations. ~SFX~ is the suffix for the new class type. + +// @uvm-ieee 1800.2-2017 auto B.5.5 +`define uvm_nonblocking_get_imp_decl(SFX) \ +class uvm_nonblocking_get_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_GET_MASK,`"uvm_nonblocking_get_imp``SFX`",IMP) \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_get_imp_decl +// +//| `uvm_get_imp_decl(SFX) +// +// Define the class uvm_get_impSFX for providing both blocking and +// non-blocking get implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.6 +`define uvm_get_imp_decl(SFX) \ +class uvm_get_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_GET_MASK,`"uvm_get_imp``SFX`",IMP) \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_blocking_peek_imp_decl +// +//| `uvm_blocking_peek_imp_decl(SFX) +// +// Define the class uvm_blocking_peek_impSFX for providing blocking peek +// implementations. ~SFX~ is the suffix for the new class type. + +// @uvm-ieee 1800.2-2017 auto B.5.7 +`define uvm_blocking_peek_imp_decl(SFX) \ +class uvm_blocking_peek_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_PEEK_MASK,`"uvm_blocking_peek_imp``SFX`",IMP) \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_peek_imp_decl +// +//| `uvm_nonblocking_peek_imp_decl(SFX) +// +// Define the class uvm_nonblocking_peek_impSFX for providing non-blocking +// peek implementations. ~SFX~ is the suffix for the new class type. + +// @uvm-ieee 1800.2-2017 auto B.5.11 +// @uvm-ieee 1800.2-2017 auto B.5.8 +`define uvm_nonblocking_peek_imp_decl(SFX) \ +class uvm_nonblocking_peek_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_PEEK_MASK,`"uvm_nonblocking_peek_imp``SFX`",IMP) \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_peek_imp_decl +// +//| `uvm_peek_imp_decl(SFX) +// +// Define the class uvm_peek_impSFX for providing both blocking and +// non-blocking peek implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.9 +`define uvm_peek_imp_decl(SFX) \ +class uvm_peek_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_PEEK_MASK,`"uvm_peek_imp``SFX`",IMP) \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ +endclass + + +// MACRO -- NODOCS -- `uvm_blocking_get_peek_imp_decl +// +//| `uvm_blocking_get_peek_imp_decl(SFX) +// +// Define the class uvm_blocking_get_peek_impSFX for providing the +// blocking get_peek implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.10 +`define uvm_blocking_get_peek_imp_decl(SFX) \ +class uvm_blocking_get_peek_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_GET_PEEK_MASK,`"uvm_blocking_get_peek_imp``SFX`",IMP) \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_get_peek_imp_decl +// +//| `uvm_nonblocking_get_peek_imp_decl(SFX) +// +// Define the class uvm_nonblocking_get_peek_impSFX for providing non-blocking +// get_peek implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.11 +`define uvm_nonblocking_get_peek_imp_decl(SFX) \ +class uvm_nonblocking_get_peek_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_GET_PEEK_MASK,`"uvm_nonblocking_get_peek_imp``SFX`",IMP) \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ +endclass + + +// MACRO -- NODOCS -- `uvm_get_peek_imp_decl +// +//| `uvm_get_peek_imp_decl(SFX) +// +// Define the class uvm_get_peek_impSFX for providing both blocking and +// non-blocking get_peek implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.12 +`define uvm_get_peek_imp_decl(SFX) \ +class uvm_get_peek_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_GET_PEEK_MASK,`"uvm_get_peek_imp``SFX`",IMP) \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_imp, T, t) \ +endclass + +// MACRO -- NODOCS -- `uvm_blocking_master_imp_decl +// +//| `uvm_blocking_master_imp_decl(SFX) +// +// Define the class uvm_blocking_master_impSFX for providing the +// blocking master implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.13 +`define uvm_blocking_master_imp_decl(SFX) \ +class uvm_blocking_master_imp``SFX #(type REQ=int, type RSP=int, type IMP=int, \ + type REQ_IMP=IMP, type RSP_IMP=IMP) \ + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); \ + typedef IMP this_imp_type; \ + typedef REQ_IMP this_req_type; \ + typedef RSP_IMP this_rsp_type; \ + `UVM_MS_IMP_COMMON(`UVM_TLM_BLOCKING_MASTER_MASK,`"uvm_blocking_master_imp``SFX`") \ + \ + `UVM_BLOCKING_PUT_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_master_imp_decl +// +//| `uvm_nonblocking_master_imp_decl(SFX) +// +// Define the class uvm_nonblocking_master_impSFX for providing the +// non-blocking master implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.14 +`define uvm_nonblocking_master_imp_decl(SFX) \ +class uvm_nonblocking_master_imp``SFX #(type REQ=int, type RSP=int, type IMP=int, \ + type REQ_IMP=IMP, type RSP_IMP=IMP) \ + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); \ + typedef IMP this_imp_type; \ + typedef REQ_IMP this_req_type; \ + typedef RSP_IMP this_rsp_type; \ + `UVM_MS_IMP_COMMON(`UVM_TLM_NONBLOCKING_MASTER_MASK,`"uvm_nonblocking_master_imp``SFX`") \ + \ + `UVM_NONBLOCKING_PUT_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + \ +endclass + +// MACRO -- NODOCS -- `uvm_master_imp_decl +// +//| `uvm_master_imp_decl(SFX) +// +// Define the class uvm_master_impSFX for providing both blocking and +// non-blocking master implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.15 +`define uvm_master_imp_decl(SFX) \ +class uvm_master_imp``SFX #(type REQ=int, type RSP=int, type IMP=int, \ + type REQ_IMP=IMP, type RSP_IMP=IMP) \ + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); \ + typedef IMP this_imp_type; \ + typedef REQ_IMP this_req_type; \ + typedef RSP_IMP this_rsp_type; \ + `UVM_MS_IMP_COMMON(`UVM_TLM_MASTER_MASK,`"uvm_master_imp``SFX`") \ + \ + `UVM_BLOCKING_PUT_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + `UVM_NONBLOCKING_PUT_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + \ +endclass + +// MACRO -- NODOCS -- `uvm_blocking_slave_imp_decl +// +//| `uvm_blocking_slave_imp_decl(SFX) +// +// Define the class uvm_blocking_slave_impSFX for providing the +// blocking slave implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.16 +`define uvm_blocking_slave_imp_decl(SFX) \ +class uvm_blocking_slave_imp``SFX #(type REQ=int, type RSP=int, type IMP=int, \ + type REQ_IMP=IMP, type RSP_IMP=IMP) \ + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); \ + typedef IMP this_imp_type; \ + typedef REQ_IMP this_req_type; \ + typedef RSP_IMP this_rsp_type; \ + `UVM_MS_IMP_COMMON(`UVM_TLM_BLOCKING_SLAVE_MASK,`"uvm_blocking_slave_imp``SFX`") \ + \ + `UVM_BLOCKING_PUT_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_slave_imp_decl +// +//| `uvm_nonblocking_slave_imp_decl(SFX) +// +// Define the class uvm_nonblocking_slave_impSFX for providing the +// non-blocking slave implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.17 +`define uvm_nonblocking_slave_imp_decl(SFX) \ +class uvm_nonblocking_slave_imp``SFX #(type REQ=int, type RSP=int, type IMP=int, \ + type REQ_IMP=IMP, type RSP_IMP=IMP) \ + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); \ + typedef IMP this_imp_type; \ + typedef REQ_IMP this_req_type; \ + typedef RSP_IMP this_rsp_type; \ + `UVM_MS_IMP_COMMON(`UVM_TLM_NONBLOCKING_SLAVE_MASK,`"uvm_nonblocking_slave_imp``SFX`") \ + \ + `UVM_NONBLOCKING_PUT_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + \ +endclass + +// MACRO -- NODOCS -- `uvm_slave_imp_decl +// +//| `uvm_slave_imp_decl(SFX) +// +// Define the class uvm_slave_impSFX for providing both blocking and +// non-blocking slave implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.18 +`define uvm_slave_imp_decl(SFX) \ +class uvm_slave_imp``SFX #(type REQ=int, type RSP=int, type IMP=int, \ + type REQ_IMP=IMP, type RSP_IMP=IMP) \ + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); \ + typedef IMP this_imp_type; \ + typedef REQ_IMP this_req_type; \ + typedef RSP_IMP this_rsp_type; \ + `UVM_MS_IMP_COMMON(`UVM_TLM_SLAVE_MASK,`"uvm_slave_imp``SFX`") \ + \ + `UVM_BLOCKING_PUT_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + `UVM_NONBLOCKING_PUT_IMP_SFX(SFX, m_rsp_imp, RSP, t) // rsp \ + \ + `UVM_BLOCKING_GET_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + `UVM_BLOCKING_PEEK_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + `UVM_NONBLOCKING_GET_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + `UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, m_req_imp, REQ, t) // req \ + \ +endclass + +// MACRO -- NODOCS -- `uvm_blocking_transport_imp_decl +// +//| `uvm_blocking_transport_imp_decl(SFX) +// +// Define the class uvm_blocking_transport_impSFX for providing the +// blocking transport implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.19 +`define uvm_blocking_transport_imp_decl(SFX) \ +class uvm_blocking_transport_imp``SFX #(type REQ=int, type RSP=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); \ + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_TRANSPORT_MASK,`"uvm_blocking_transport_imp``SFX`",IMP) \ + `UVM_BLOCKING_TRANSPORT_IMP_SFX(SFX, m_imp, REQ, RSP, req, rsp) \ +endclass + +// MACRO -- NODOCS -- `uvm_nonblocking_transport_imp_decl +// +//| `uvm_nonblocking_transport_imp_decl(SFX) +// +// Define the class uvm_nonblocking_transport_impSFX for providing the +// non-blocking transport implementation. + +// @uvm-ieee 1800.2-2017 auto B.5.20 +`define uvm_nonblocking_transport_imp_decl(SFX) \ +class uvm_nonblocking_transport_imp``SFX #(type REQ=int, type RSP=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); \ + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_TRANSPORT_MASK,`"uvm_nonblocking_transport_imp``SFX`",IMP) \ + `UVM_NONBLOCKING_TRANSPORT_IMP_SFX(SFX, m_imp, REQ, RSP, req, rsp) \ +endclass + +`define uvm_non_blocking_transport_imp_decl(SFX) \ + `uvm_nonblocking_transport_imp_decl(SFX) + +// MACRO -- NODOCS -- `uvm_transport_imp_decl +// +//| `uvm_transport_imp_decl(SFX) +// +// Define the class uvm_transport_impSFX for providing both blocking and +// non-blocking transport implementations. ~SFX~ is the suffix for the new class +// type. + +// @uvm-ieee 1800.2-2017 auto B.5.21 +`define uvm_transport_imp_decl(SFX) \ +class uvm_transport_imp``SFX #(type REQ=int, type RSP=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); \ + `UVM_IMP_COMMON(`UVM_TLM_TRANSPORT_MASK,`"uvm_transport_imp``SFX`",IMP) \ + `UVM_BLOCKING_TRANSPORT_IMP_SFX(SFX, m_imp, REQ, RSP, req, rsp) \ + `UVM_NONBLOCKING_TRANSPORT_IMP_SFX(SFX, m_imp, REQ, RSP, req, rsp) \ +endclass + +// MACRO -- NODOCS -- `uvm_analysis_imp_decl +// +//| `uvm_analysis_imp_decl(SFX) +// +// Define the class uvm_analysis_impSFX for providing an analysis +// implementation. ~SFX~ is the suffix for the new class type. The analysis +// implementation is the write function. The `uvm_analysis_imp_decl allows +// for a scoreboard (or other analysis component) to support input from many +// places. For example: +// +//| `uvm_analysis_imp_decl(_ingress) +//| `uvm_analysis_imp_decl(_egress) +//| +//| class myscoreboard extends uvm_component; +//| uvm_analysis_imp_ingress#(mydata, myscoreboard) ingress; +//| uvm_analysis_imp_egress#(mydata, myscoreboard) egress; +//| mydata ingress_list[$]; +//| ... +//| +//| function new(string name, uvm_component parent); +//| super.new(name,parent); +//| ingress = new("ingress", this); +//| egress = new("egress", this); +//| endfunction +//| +//| function void write_ingress(mydata t); +//| ingress_list.push_back(t); +//| endfunction +//| +//| function void write_egress(mydata t); +//| find_match_in_ingress_list(t); +//| endfunction +//| +//| function void find_match_in_ingress_list(mydata t); +//| //implement scoreboarding for this particular dut +//| ... +//| endfunction +//| endclass + +// @uvm-ieee 1800.2-2017 auto B.5.22 +`define uvm_analysis_imp_decl(SFX) \ +class uvm_analysis_imp``SFX #(type T=int, type IMP=int) \ + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \ + `UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,`"uvm_analysis_imp``SFX`",IMP) \ + function void write( input T t); \ + m_imp.write``SFX( t); \ + endfunction \ + \ +endclass + + +// These imps are used in uvm_*_port, uvm_*_export and uvm_*_imp, using suffixes +// + +`define UVM_BLOCKING_PUT_IMP_SFX(SFX, imp, TYPE, arg) \ + task put( input TYPE arg); imp.put``SFX( arg); endtask + +`define UVM_BLOCKING_GET_IMP_SFX(SFX, imp, TYPE, arg) \ + task get( output TYPE arg); imp.get``SFX( arg); endtask + +`define UVM_BLOCKING_PEEK_IMP_SFX(SFX, imp, TYPE, arg) \ + task peek( output TYPE arg);imp.peek``SFX( arg); endtask + +`define UVM_NONBLOCKING_PUT_IMP_SFX(SFX, imp, TYPE, arg) \ + function bit try_put( input TYPE arg); \ + if( !imp.try_put``SFX( arg)) return 0; \ + return 1; \ + endfunction \ + function bit can_put(); return imp.can_put``SFX(); endfunction + +`define UVM_NONBLOCKING_GET_IMP_SFX(SFX, imp, TYPE, arg) \ + function bit try_get( output TYPE arg); \ + if( !imp.try_get``SFX( arg)) return 0; \ + return 1; \ + endfunction \ + function bit can_get(); return imp.can_get``SFX(); endfunction + +`define UVM_NONBLOCKING_PEEK_IMP_SFX(SFX, imp, TYPE, arg) \ + function bit try_peek( output TYPE arg); \ + if( !imp.try_peek``SFX( arg)) return 0; \ + return 1; \ + endfunction \ + function bit can_peek(); return imp.can_peek``SFX(); endfunction + +`define UVM_BLOCKING_TRANSPORT_IMP_SFX(SFX, imp, REQ, RSP, req_arg, rsp_arg) \ + task transport( input REQ req_arg, output RSP rsp_arg); \ + imp.transport``SFX(req_arg, rsp_arg); \ + endtask + +`define UVM_NONBLOCKING_TRANSPORT_IMP_SFX(SFX, imp, REQ, RSP, req_arg, rsp_arg) \ + function bit nb_transport( input REQ req_arg, output RSP rsp_arg); \ + if(imp) return imp.nb_transport``SFX(req_arg, rsp_arg); \ + endfunction + +//---------------------------------------------------------------------- +// imp definitions +//---------------------------------------------------------------------- +`define UVM_SEQ_ITEM_PULL_IMP(imp, REQ, RSP, req_arg, rsp_arg) \ + function void disable_auto_item_recording(); imp.disable_auto_item_recording(); endfunction \ + function bit is_auto_item_recording_enabled(); return imp.is_auto_item_recording_enabled(); endfunction \ + task get_next_item(output REQ req_arg); imp.get_next_item(req_arg); endtask \ + task try_next_item(output REQ req_arg); imp.try_next_item(req_arg); endtask \ + function void item_done(input RSP rsp_arg = null); imp.item_done(rsp_arg); endfunction \ + task wait_for_sequences(); imp.wait_for_sequences(); endtask \ + function bit has_do_available(); return imp.has_do_available(); endfunction \ + function void put_response(input RSP rsp_arg); imp.put_response(rsp_arg); endfunction \ + task get(output REQ req_arg); imp.get(req_arg); endtask \ + task peek(output REQ req_arg); imp.peek(req_arg); endtask \ + task put(input RSP rsp_arg); imp.put(rsp_arg); endtask + +// primitive interfaces +`define UVM_TLM_BLOCKING_PUT_MASK (1<<0) +`define UVM_TLM_BLOCKING_GET_MASK (1<<1) +`define UVM_TLM_BLOCKING_PEEK_MASK (1<<2) +`define UVM_TLM_BLOCKING_TRANSPORT_MASK (1<<3) + +`define UVM_TLM_NONBLOCKING_PUT_MASK (1<<4) +`define UVM_TLM_NONBLOCKING_GET_MASK (1<<5) +`define UVM_TLM_NONBLOCKING_PEEK_MASK (1<<6) +`define UVM_TLM_NONBLOCKING_TRANSPORT_MASK (1<<7) + +`define UVM_TLM_ANALYSIS_MASK (1<<8) + +`define UVM_TLM_MASTER_BIT_MASK (1<<9) +`define UVM_TLM_SLAVE_BIT_MASK (1<<10) +// combination interfaces +`define UVM_TLM_PUT_MASK (`UVM_TLM_BLOCKING_PUT_MASK | `UVM_TLM_NONBLOCKING_PUT_MASK) +`define UVM_TLM_GET_MASK (`UVM_TLM_BLOCKING_GET_MASK | `UVM_TLM_NONBLOCKING_GET_MASK) +`define UVM_TLM_PEEK_MASK (`UVM_TLM_BLOCKING_PEEK_MASK | `UVM_TLM_NONBLOCKING_PEEK_MASK) + +`define UVM_TLM_BLOCKING_GET_PEEK_MASK (`UVM_TLM_BLOCKING_GET_MASK | `UVM_TLM_BLOCKING_PEEK_MASK) +`define UVM_TLM_BLOCKING_MASTER_MASK (`UVM_TLM_BLOCKING_PUT_MASK | `UVM_TLM_BLOCKING_GET_MASK | `UVM_TLM_BLOCKING_PEEK_MASK | `UVM_TLM_MASTER_BIT_MASK) +`define UVM_TLM_BLOCKING_SLAVE_MASK (`UVM_TLM_BLOCKING_PUT_MASK | `UVM_TLM_BLOCKING_GET_MASK | `UVM_TLM_BLOCKING_PEEK_MASK | `UVM_TLM_SLAVE_BIT_MASK) + +`define UVM_TLM_NONBLOCKING_GET_PEEK_MASK (`UVM_TLM_NONBLOCKING_GET_MASK | `UVM_TLM_NONBLOCKING_PEEK_MASK) +`define UVM_TLM_NONBLOCKING_MASTER_MASK (`UVM_TLM_NONBLOCKING_PUT_MASK | `UVM_TLM_NONBLOCKING_GET_MASK | `UVM_TLM_NONBLOCKING_PEEK_MASK | `UVM_TLM_MASTER_BIT_MASK) +`define UVM_TLM_NONBLOCKING_SLAVE_MASK (`UVM_TLM_NONBLOCKING_PUT_MASK | `UVM_TLM_NONBLOCKING_GET_MASK | `UVM_TLM_NONBLOCKING_PEEK_MASK | `UVM_TLM_SLAVE_BIT_MASK) + +`define UVM_TLM_GET_PEEK_MASK (`UVM_TLM_GET_MASK | `UVM_TLM_PEEK_MASK) +`define UVM_TLM_MASTER_MASK (`UVM_TLM_BLOCKING_MASTER_MASK | `UVM_TLM_NONBLOCKING_MASTER_MASK) +`define UVM_TLM_SLAVE_MASK (`UVM_TLM_BLOCKING_SLAVE_MASK | `UVM_TLM_NONBLOCKING_SLAVE_MASK) +`define UVM_TLM_TRANSPORT_MASK (`UVM_TLM_BLOCKING_TRANSPORT_MASK | `UVM_TLM_NONBLOCKING_TRANSPORT_MASK) + +`define UVM_SEQ_ITEM_GET_NEXT_ITEM_MASK (1<<0) +`define UVM_SEQ_ITEM_TRY_NEXT_ITEM_MASK (1<<1) +`define UVM_SEQ_ITEM_ITEM_DONE_MASK (1<<2) +`define UVM_SEQ_ITEM_HAS_DO_AVAILABLE_MASK (1<<3) +`define UVM_SEQ_ITEM_WAIT_FOR_SEQUENCES_MASK (1<<4) +`define UVM_SEQ_ITEM_PUT_RESPONSE_MASK (1<<5) +`define UVM_SEQ_ITEM_PUT_MASK (1<<6) +`define UVM_SEQ_ITEM_GET_MASK (1<<7) +`define UVM_SEQ_ITEM_PEEK_MASK (1<<8) + +`define UVM_SEQ_ITEM_PULL_MASK (`UVM_SEQ_ITEM_GET_NEXT_ITEM_MASK | `UVM_SEQ_ITEM_TRY_NEXT_ITEM_MASK | \ + `UVM_SEQ_ITEM_ITEM_DONE_MASK | `UVM_SEQ_ITEM_HAS_DO_AVAILABLE_MASK | \ + `UVM_SEQ_ITEM_WAIT_FOR_SEQUENCES_MASK | `UVM_SEQ_ITEM_PUT_RESPONSE_MASK | \ + `UVM_SEQ_ITEM_PUT_MASK | `UVM_SEQ_ITEM_GET_MASK | `UVM_SEQ_ITEM_PEEK_MASK) + +`define UVM_SEQ_ITEM_UNI_PULL_MASK (`UVM_SEQ_ITEM_GET_NEXT_ITEM_MASK | `UVM_SEQ_ITEM_TRY_NEXT_ITEM_MASK | \ + `UVM_SEQ_ITEM_ITEM_DONE_MASK | `UVM_SEQ_ITEM_HAS_DO_AVAILABLE_MASK | \ + `UVM_SEQ_ITEM_WAIT_FOR_SEQUENCES_MASK | `UVM_SEQ_ITEM_GET_MASK | \ + `UVM_SEQ_ITEM_PEEK_MASK) + +`define UVM_SEQ_ITEM_PUSH_MASK (`UVM_SEQ_ITEM_PUT_MASK) + +`include "tlm1/uvm_tlm_imps.svh" diff --git a/test_regress/t/t_uvm/macros/uvm_undefineall.svh b/test_regress/t/t_uvm/macros/uvm_undefineall.svh new file mode 100644 index 0000000000..7018199854 --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_undefineall.svh @@ -0,0 +1,86 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- +// This file undefs all macros that are defined by the UVM library. This can +// be used to load uvm into multiple scopes using a single compilation. + +`undef UVM_BLOCKING_GET_IMP +`undef UVM_BLOCKING_GET_IMP_SFX +`undef UVM_BLOCKING_GET_PEEK_IMP +`undef UVM_BLOCKING_PEEK_IMP +`undef UVM_BLOCKING_PEEK_IMP_SFX +`undef UVM_BLOCKING_PUT_IMP +`undef UVM_BLOCKING_PUT_IMP_SFX +`undef UVM_BLOCKING_TRANSPORT_IMP +`undef UVM_BLOCKING_TRANSPORT_IMP_SFX +`undef DODEEPCOPY +`undef DOREFERENCECOPY +`undef DOSHALLOWCOPY +`undef UVM_FUNCTION_ERROR +`undef UVM_GET_IMP +`undef UVM_GET_PEEK_IMP +`undef M_RESIZE_QUEUE_COPY +`undef M_RESIZE_QUEUE_NOCOPY +`undef M_RESIZE_QUEUE_OBJECT_COPY +`undef M_RESIZE_QUEUE_OBJECT_NOCOPY +`undef m_uvm_record_any_object +`undef m_uvm_record_array_int +`undef m_uvm_record_array_object +`undef m_uvm_record_array_string +`undef m_uvm_record_int +`undef m_uvm_record_object +`undef m_uvm_record_qda_enum +`undef m_uvm_record_string +`undef UVM_NONBLOCKING_GET_IMP +`undef UVM_NONBLOCKING_GET_IMP_SFX +`undef UVM_NONBLOCKING_GET_PEEK_IMP +`undef UVM_NONBLOCKING_PEEK_IMP +`undef UVM_NONBLOCKING_PEEK_IMP_SFX +`undef UVM_NONBLOCKING_PUT_IMP +`undef UVM_NONBLOCKING_PUT_IMP_SFX +`undef UVM_NONBLOCKING_TRANSPORT_IMP +`undef UVM_NONBLOCKING_TRANSPORT_IMP_SFX +`undef UVM_PEEK_IMP +`undef print_enum_field +`undef print_integral_field +`undef _protected +`undef UVM_PUT_IMP +`undef UVM_SEQ_ITEM_FUNCTION_ERROR +`undef UVM_SEQ_ITEM_GET_MASK +`undef UVM_SEQ_ITEM_GET_NEXT_ITEM_MASK +`undef UVM_SEQ_ITEM_HAS_DO_AVAILABLE_MASK +`undef UVM_SEQ_ITEM_ITEM_DONE_MASK +`undef UVM_SEQ_ITEM_PEEK_MASK +`undef UVM_SEQ_ITEM_PULL_IMP +`undef UVM_SEQ_ITEM_PULL_MASK +`undef UVM_SEQ_ITEM_PUSH_MASK +`undef UVM_SEQ_ITEM_PUT_MASK +`undef UVM_SEQ_ITEM_PUT_RESPONSE_MASK +`undef UVM_SEQ_ITEM_TASK_ERROR +`undef UVM_SEQ_ITEM_TRY_NEXT_ITEM_MASK +`undef UVM_SEQ_ITEM_UNI_PULL_MASK +`undef UVM_SEQ_ITEM_WAIT_FOR_SEQUENCES_MASK +`undef UVM_TASK_ERROR +`undef UVM_TRANSPORT_IMP +`undef _UVM_CB_MSG_NO_CBS +`undef _UVM_CB_MSG_NOT_REG +`undef _UVM_CB_MSG_NULL_CB +`undef _UVM_CB_MSG_NULL_OBJ +`undef UVM_XCELIUM diff --git a/test_regress/t/t_uvm/macros/uvm_version_defines.svh b/test_regress/t/t_uvm/macros/uvm_version_defines.svh new file mode 100644 index 0000000000..070562616e --- /dev/null +++ b/test_regress/t/t_uvm/macros/uvm_version_defines.svh @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------- +// Copyright 2011-2012 Paradigm Works +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2015 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//---------------------------------------------------------------------- + +`ifndef UVM_VERSION_DEFINES_SVH +`define UVM_VERSION_DEFINES_SVH + +`define UVM_VERSION 2016 + + +// Title --NODOCS-- UVM Version Defines + +// Group --NODOCS-- UVM Version Ladder +// The following defines are provided as an indication of +// how this implementation release relates to previous UVM +// implementation releases from Accellera. + +`ifdef UVM_ENABLE_DEPRECATED_API +// Macro --NODOCS-- UVM_POST_VERSION_1_1 +// Indicates that this version of the UVM came after the +// 1.1 versions, including the various 1.1 fix revisions. +`define UVM_POST_VERSION_1_1 +`endif // UVM_ENABLE_DEPRECATED_API + +`endif // UVM_VERSION_DEFINES_SVH diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_mem_access_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_mem_access_seq.svh new file mode 100644 index 0000000000..4e9d7bc039 --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_mem_access_seq.svh @@ -0,0 +1,313 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2015-2018 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. +// ------------------------------------------------------------- +// + +// +// TITLE -- NODOCS -- Memory Access Test Sequence +// + +// +// class -- NODOCS -- uvm_mem_single_access_seq +// +// Verify the accessibility of a memory +// by writing through its default address map +// then reading it via the backdoor, then reversing the process, +// making sure that the resulting value matches the written value. +// +// If bit-type resource named +// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the memory, +// the memory is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.mem0.get_full_name()}, +//| "NO_MEM_TESTS", 1, this); +// +// Memories without an available backdoor +// cannot be tested. +// +// The DUT should be idle and not modify the memory during this test. +// + +// @uvm-ieee 1800.2-2017 auto E.5.1.1 +class uvm_mem_single_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- mem + // + // The memory to be tested + // + uvm_mem mem; + + `uvm_object_utils(uvm_mem_single_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.5.1.3 + function new(string name="uam_mem_single_access_seq"); + super.new(name); + endfunction + + virtual task body(); + string mode; + uvm_reg_map maps[$]; + int n_bits; + + if (mem == null) begin + `uvm_error("uvm_mem_access_seq", "No register specified to run sequence on") + return; + end + + // Memories with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_MEM_ACCESS_TEST", 0) != null) + return; + + // Can only deal with memories with backdoor access + if (mem.get_backdoor() == null && !mem.has_hdl_path()) begin + `uvm_error("uvm_mem_access_seq", {"Memory '",mem.get_full_name(), + "' does not have a backdoor mechanism available"}) + return; + end + + n_bits = mem.get_n_bits(); + + // Memories may be accessible from multiple physical interfaces (maps) + mem.get_maps(maps); + + // Walk the memory via each map + foreach (maps[j]) begin + uvm_status_e status; + uvm_reg_data_t val, exp, v; + + `uvm_info("uvm_mem_access_seq", {"Verifying access of memory '", + mem.get_full_name(),"' in map '", maps[j].get_full_name(), + "' ..."}, UVM_LOW) + + mode = mem.get_access(maps[j]); + + // The access process is, for address k: + // - Write random value via front door + // - Read via backdoor and expect same random value if RW + // - Write complement of random value via back door + // - Read via front door and expect inverted random value + for (int k = 0; k < mem.get_size(); k++) begin + val = $random & uvm_reg_data_t'((1'b1< 32) + val = uvm_reg_data_t'(val << 32) | $random; + if (mode == "RO") begin + mem.peek(status, k, exp); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.", + status.name(), mem.get_full_name(), k)) + end + end + else exp = val; + + mem.write(status, k, val, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when writing \"%s[%0d]\" through map \"%s\".", + status.name(), mem.get_full_name(), k, maps[j].get_full_name())) + end + #1; + + val = 'x; + mem.peek(status, k, val); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.", + status.name(), mem.get_full_name(), k)) + end + else begin + if (val !== exp) begin + `uvm_error("uvm_mem_access_seq", $sformatf("Backdoor \"%s[%0d]\" read back as 'h%h instead of 'h%h.", + mem.get_full_name(), k, val, exp)) + end + end + + exp = ~exp & ((1'b1< sequence on +// every memory within it. +// +// If bit-type resource named +// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the block, +// the block is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"}, +//| "NO_MEM_TESTS", 1, this); +// + +// @uvm-ieee 1800.2-2017 auto E.5.2.1 +class uvm_mem_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- model + // + // The block to be tested. Declared in the base class. + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- mem_seq + // + // The sequence used to test one memory + // + protected uvm_mem_single_access_seq mem_seq; + + `uvm_object_utils(uvm_mem_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.5.2.3.1 + function new(string name="uvm_mem_access_seq"); + super.new(name); + endfunction + + + // @uvm-ieee 1800.2-2017 auto E.5.2.3.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_mem_access_seq", "No register model specified to run sequence on") + return; + end + + uvm_report_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + +`ifdef VERILATOR + mem_seq = uvm_mem_single_access_seq::type_id_create("single_mem_access_seq"); +`else + mem_seq = uvm_mem_single_access_seq::type_id::create("single_mem_access_seq"); +`endif + + this.reset_blk(model); + model.reset(); + + do_block(model); + endtask: body + + + // Task -- NODOCS -- do_block + // + // Test all of the memories in a given ~block~ + // + protected virtual task do_block(uvm_reg_block blk); + uvm_mem mems[$]; + + if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_MEM_ACCESS_TEST", 0) != null ) + return; + + // Iterate over all memories, checking accesses + blk.get_memories(mems, UVM_NO_HIER); + foreach (mems[i]) begin + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_MEM_ACCESS_TEST", 0) != null ) + continue; + + // Can only deal with memories with backdoor access + if (mems[i].get_backdoor() == null && + !mems[i].has_hdl_path()) begin + `uvm_warning("uvm_mem_access_seq", $sformatf("Memory \"%s\" does not have a backdoor mechanism available", + mems[i].get_full_name())) + continue; + end + + mem_seq.mem = mems[i]; + mem_seq.start(null, this); + end + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i]); + end + end + endtask: do_block + + + // Task -- NODOCS -- reset_blk + // + // Reset the DUT that corresponds to the specified block abstraction class. + // + // Currently empty. + // Will rollback the environment's phase to the ~reset~ + // phase once the new phasing is available. + // + // In the meantime, the DUT should be reset before executing this + // test sequence or this method should be implemented + // in an extension to reset the DUT. + // + virtual task reset_blk(uvm_reg_block blk); + endtask + + +endclass: uvm_mem_access_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_mem_walk_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_mem_walk_seq.svh new file mode 100644 index 0000000000..e90eda43f7 --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_mem_walk_seq.svh @@ -0,0 +1,307 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Memory Walking-Ones Test Sequences +// +// This section defines sequences for applying a "walking-ones" +// algorithm on one or more memories. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_mem_single_walk_seq +// +// Runs the walking-ones algorithm on the memory given by the property, +// which must be assigned prior to starting this sequence. +// +// If bit-type resource named +// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_WALK_TEST" +// in the "REG::" namespace +// matches the full name of the memory, +// the memory is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.mem0.get_full_name()}, +//| "NO_MEM_TESTS", 1, this); +// +// The walking ones algorithm is performed for each map in which the memory +// is defined. +// +//| for (k = 0 thru memsize-1) +//| write addr=k data=~k +//| if (k > 0) { +//| read addr=k-1, expect data=~(k-1) +//| write addr=k-1 data=k-1 +//| if (k == last addr) +//| read addr=k, expect data=~k +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.6.1.1 +class uvm_mem_single_walk_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + `uvm_object_utils(uvm_mem_single_walk_seq) + + + // Variable -- NODOCS -- mem + // + // The memory to test; must be assigned prior to starting sequence. + + uvm_mem mem; + + + // Function -- NODOCS -- new + // + // Creates a new instance of the class with the given name. + + // @uvm-ieee 1800.2-2017 auto E.6.1.3.1 + function new(string name="uvm_mem_walk_seq"); + super.new(name); + endfunction + + + // Task -- NODOCS -- body + // + // Performs the walking-ones algorithm on each map of the memory + // specified in . + + // @uvm-ieee 1800.2-2017 auto E.6.1.3.2 + virtual task body(); + uvm_reg_map maps[$]; + int n_bits; + + if (mem == null) begin + `uvm_error("uvm_mem_walk_seq", "No memory specified to run sequence on") + return; + end + + // Memories with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_MEM_WALK_TEST", 0) != null ) + return; + + n_bits = mem.get_n_bits(); + + // Memories may be accessible from multiple physical interfaces (maps) + mem.get_maps(maps); + + // Walk the memory via each map + foreach (maps[j]) begin + uvm_status_e status; + uvm_reg_data_t val, exp, v; + + // Only deal with RW memories + if (mem.get_access(maps[j]) != "RW") continue; + + `uvm_info("uvm_mem_walk_seq", $sformatf("Walking memory %s in map \"%s\"...", + mem.get_full_name(), maps[j].get_full_name()), UVM_LOW) + + // The walking process is, for address k: + // - Write ~k + // - Read k-1 and expect ~(k-1) if k > 0 + // - Write k-1 at k-1 + // - Read k and expect ~k if k == last address + for (int k = 0; k < mem.get_size(); k++) begin + mem.write(status, k, ~k, UVM_FRONTDOOR, maps[j], this); + + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_walk_seq", $sformatf("Status was %s when writing \"%s[%0d]\" through map \"%s\".", + status.name(), mem.get_full_name(), k, maps[j].get_full_name())) + end + + if (k > 0) begin + mem.read(status, k-1, val, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_walk_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through map \"%s\".", + status.name(), mem.get_full_name(), k, maps[j].get_full_name())) + end + else begin + exp = ~(k-1) & ((1'b1< sequence on +// every memory within it. +// +// If bit-type resource named +// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_WALK_TEST" +// in the "REG::" namespace +// matches the full name of the block, +// the block is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"}, +//| "NO_MEM_TESTS", 1, this); +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.6.2.1 +class uvm_mem_walk_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- model + // + // The block to be tested. Declared in the base class. + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- mem_seq + // + // The sequence used to test one memory + // + protected uvm_mem_single_walk_seq mem_seq; + + `uvm_object_utils(uvm_mem_walk_seq) + + // @uvm-ieee 1800.2-2017 auto E.6.3.1 + function new(string name="uvm_mem_walk_seq"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto E.6.3.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_mem_walk_seq", "No register model specified to run sequence on") + return; + end + + uvm_report_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + +`ifdef VERILATOR + mem_seq = uvm_mem_single_walk_seq::type_id_create("single_mem_walk_seq"); +`else + mem_seq = uvm_mem_single_walk_seq::type_id::create("single_mem_walk_seq"); +`endif + + this.reset_blk(model); + model.reset(); + + do_block(model); + endtask: body + + + // Task -- NODOCS -- do_block + // + // Test all of the memories in a given ~block~ + // + protected virtual task do_block(uvm_reg_block blk); + uvm_mem mems[$]; + + if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_MEM_ACCESS_TEST", 0) != null ) + return; + + // Iterate over all memories, checking accesses + blk.get_memories(mems, UVM_NO_HIER); + foreach (mems[i]) begin + // Memories with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_MEM_WALK_TEST", 0) != null ) + continue; + + mem_seq.mem = mems[i]; + mem_seq.start(null, this); + end + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i]); + end + end + endtask: do_block + + + // Task -- NODOCS -- reset_blk + // + // Reset the DUT that corresponds to the specified block abstraction class. + // + // Currently empty. + // Will rollback the environment's phase to the ~reset~ + // phase once the new phasing is available. + // + // In the meantime, the DUT should be reset before executing this + // test sequence or this method should be implemented + // in an extension to reset the DUT. + // + virtual task reset_blk(uvm_reg_block blk); + endtask + +endclass: uvm_mem_walk_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_reg_access_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_reg_access_seq.svh new file mode 100644 index 0000000000..35c083603c --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_reg_access_seq.svh @@ -0,0 +1,374 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2015 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. +// ------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// +// Title -- NODOCS -- Register Access Test Sequences +// +// This section defines sequences that test DUT register access via the +// available frontdoor and backdoor paths defined in the provided register +// model. +//------------------------------------------------------------------------------ + +typedef class uvm_mem_access_seq; + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_reg_single_access_seq +// +// Verify the accessibility of a register +// by writing through its default address map +// then reading it via the backdoor, then reversing the process, +// making sure that the resulting value matches the mirrored value. +// +// If bit-type resource named +// "NO_REG_TESTS" or "NO_REG_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the register, +// the register is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.r0.get_full_name()}, +//| "NO_REG_TESTS", 1, this); +// +// Registers without an available backdoor or +// that contain read-only fields only, +// or fields with unknown access policies +// cannot be tested. +// +// The DUT should be idle and not modify any register during this test. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.3.1.1 +class uvm_reg_single_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- rg + // The register to be tested + uvm_reg rg; + + `uvm_object_utils(uvm_reg_single_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.3.1.3 + function new(string name="uvm_reg_single_access_seq"); + super.new(name); + endfunction + + virtual task body(); + uvm_reg_map maps[$]; + + if (rg == null) begin + `uvm_error("uvm_reg_access_seq", "No register specified to run sequence on") + return; + end + + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()}, + "NO_REG_ACCESS_TEST", 0) != null ) + return; + + // Can only deal with registers with backdoor access + if (rg.get_backdoor() == null && !rg.has_hdl_path()) begin + `uvm_error("uvm_reg_access_seq", {"Register '",rg.get_full_name(), + "' does not have a backdoor mechanism available"}) + return; + end + + // Registers may be accessible from multiple physical interfaces (maps) + rg.get_maps(maps); + + // Cannot test access if register contains RO or OTHER fields + begin + uvm_reg_field fields[$]; + + rg.get_fields(fields); + foreach (maps[k]) begin + int ro; + ro=0; + foreach (fields[j]) begin + if (fields[j].get_access(maps[k]) == "RO") begin + ro++; + end + if (!fields[j].is_known_access(maps[k])) begin + `uvm_warning("uvm_reg_access_seq", {"Register '",rg.get_full_name(), + "' has field with unknown access type '", + fields[j].get_access(maps[k]),"', skipping"}) + return; + end + end + if(ro==fields.size()) begin + `uvm_warning("uvm_reg_access_seq", {"Register '", + rg.get_full_name(),"' has only RO fields in map ",maps[k].get_full_name(),", skipping"}) + return; + end + end + end + + // Access each register: + // - Write complement of reset value via front door + // - Read value via backdoor and compare against mirror + // - Write reset value via backdoor + // - Read via front door and compare against mirror + foreach (maps[j]) begin + uvm_status_e status; + uvm_reg_data_t v, exp; + + `uvm_info("uvm_reg_access_seq", {"Verifying access of register '", + rg.get_full_name(),"' in map '", maps[j].get_full_name(), + "' ..."}, UVM_LOW) + + v = rg.get(); + + rg.write(status, ~v, UVM_FRONTDOOR, maps[j], this); + + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_access_seq", {"Status was '",status.name(), + "' when writing '",rg.get_full_name(), + "' through map '",maps[j].get_full_name(),"'"}) + end + #1; + + rg.mirror(status, UVM_CHECK, UVM_BACKDOOR, uvm_reg_map::backdoor(), this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_access_seq", {"Status was '",status.name(), + "' when reading reset value of register '", + rg.get_full_name(), "' through backdoor"}) + end + + rg.write(status, v, UVM_BACKDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_access_seq", {"Status was '",status.name(), + "' when writing '",rg.get_full_name(), + "' through backdoor"}) + end + + rg.mirror(status, UVM_CHECK, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_access_seq", {"Status was '",status.name(), + "' when reading reset value of register '", + rg.get_full_name(), "' through map '", + maps[j].get_full_name(),"'"}) + end + end + endtask: body +endclass: uvm_reg_single_access_seq + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_reg_access_seq +// +// Verify the accessibility of all registers in a block +// by executing the sequence on +// every register within it. +// +// If bit-type resource named +// "NO_REG_TESTS" or "NO_REG_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the block, +// the block is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"}, +//| "NO_REG_TESTS", 1, this); +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.3.2.1 +class uvm_reg_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- model + // + // The block to be tested. Declared in the base class. + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- reg_seq + // + // The sequence used to test one register + // + protected uvm_reg_single_access_seq reg_seq; + + `uvm_object_utils(uvm_reg_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.3.2.3.1 + function new(string name="uvm_reg_access_seq"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto E.3.2.3.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_reg_access_seq", "No register model specified to run sequence on") + return; + end + + uvm_report_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + +`ifdef VERILATOR + reg_seq = uvm_reg_single_access_seq::type_id_create("single_reg_access_seq"); +`else + reg_seq = uvm_reg_single_access_seq::type_id::create("single_reg_access_seq"); +`endif + + this.reset_blk(model); + model.reset(); + + do_block(model); + endtask: body + + + // Task -- NODOCS -- do_block + // + // Test all of the registers in a block + // + protected virtual task do_block(uvm_reg_block blk); + uvm_reg regs[$]; + + if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_ACCESS_TEST", 0) != null ) + return; + + // Iterate over all registers, checking accesses + blk.get_registers(regs, UVM_NO_HIER); + foreach (regs[i]) begin + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()}, + "NO_REG_ACCESS_TEST", 0) != null ) + continue; + + // Can only deal with registers with backdoor access + if (regs[i].get_backdoor() == null && !regs[i].has_hdl_path()) begin + `uvm_warning("uvm_reg_access_seq", {"Register '",regs[i].get_full_name(), + "' does not have a backdoor mechanism available"}) + continue; + end + + reg_seq.rg = regs[i]; + reg_seq.start(null,this); + end + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i]); + end + end + endtask: do_block + + + // Task -- NODOCS -- reset_blk + // + // Reset the DUT that corresponds to the specified block abstraction class. + // + // Currently empty. + // Will rollback the environment's phase to the ~reset~ + // phase once the new phasing is available. + // + // In the meantime, the DUT should be reset before executing this + // test sequence or this method should be implemented + // in an extension to reset the DUT. + // + virtual task reset_blk(uvm_reg_block blk); + endtask + +endclass: uvm_reg_access_seq + + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_reg_mem_access_seq +// +// Verify the accessibility of all registers and memories in a block +// by executing the and +// sequence respectively on every register +// and memory within it. +// +// Blocks and registers with the NO_REG_TESTS or +// the NO_REG_ACCESS_TEST attribute are not verified. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.3.3.1 +class uvm_reg_mem_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + `uvm_object_utils(uvm_reg_mem_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.3.3.2 + function new(string name="uvm_reg_mem_access_seq"); + super.new(name); + endfunction + + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_reg_mem_access_seq", "Register model handle is null") + return; + end + + uvm_report_info("STARTING_SEQ", + {"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + + if (uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null) begin + if (uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_ACCESS_TEST", 0) == null) begin + uvm_reg_access_seq sub_seq = new("reg_access_seq"); + this.reset_blk(model); + model.reset(); + sub_seq.model = model; + sub_seq.start(null,this); + end + if (uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_MEM_ACCESS_TEST", 0) == null) begin + uvm_mem_access_seq sub_seq = new("mem_access_seq"); + this.reset_blk(model); + model.reset(); + sub_seq.model = model; + sub_seq.start(null,this); + end + end + + endtask: body + + + // Any additional steps required to reset the block + // and make it accessibl + virtual task reset_blk(uvm_reg_block blk); + endtask + + +endclass: uvm_reg_mem_access_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_reg_bit_bash_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_reg_bit_bash_seq.svh new file mode 100644 index 0000000000..2884086666 --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_reg_bit_bash_seq.svh @@ -0,0 +1,310 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2013 Semifore +// Copyright 2004-2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Bit Bashing Test Sequences +//------------------------------------------------------------------------------ +// This section defines classes that test individual bits of the registers +// defined in a register model. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_single_bit_bash_seq +// +// Verify the implementation of a single register +// by attempting to write 1's and 0's to every bit in it, +// via every address map in which the register is mapped, +// making sure that the resulting value matches the mirrored value. +// +// If bit-type resource named +// "NO_REG_TESTS" or "NO_REG_BIT_BASH_TEST" +// in the "REG::" namespace +// matches the full name of the register, +// the register is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.r0.get_full_name()}, +//| "NO_REG_TESTS", 1, this); +// +// Registers that contain fields with unknown access policies +// cannot be tested. +// +// The DUT should be idle and not modify any register during this test. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.2.1.1 +class uvm_reg_single_bit_bash_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- rg + // The register to be tested + uvm_reg rg; + + `uvm_object_utils(uvm_reg_single_bit_bash_seq) + + // @uvm-ieee 1800.2-2017 auto E.2.1.3 + function new(string name="uvm_reg_single_bit_bash_seq"); + super.new(name); + endfunction + + virtual task body(); + uvm_reg_field fields[$]; + string mode[`UVM_REG_DATA_WIDTH]; + uvm_reg_map maps[$]; + uvm_reg_data_t dc_mask; + uvm_reg_data_t reset_val; + int n_bits; + string field_access; + + if (rg == null) begin + `uvm_error("uvm_reg_bit_bash_seq", "No register specified to run sequence on") + return; + end + + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()}, + "NO_REG_BIT_BASH_TEST", 0) != null ) + return; + + n_bits = rg.get_n_bytes() * 8; + + // Let's see what kind of bits we have... + rg.get_fields(fields); + + // Registers may be accessible from multiple physical interfaces (maps) + rg.get_maps(maps); + + // Bash the bits in the register via each map + foreach (maps[j]) begin + uvm_status_e status; + uvm_reg_data_t val, exp, v; + int next_lsb; + + next_lsb = 0; + dc_mask = 0; + foreach (fields[k]) begin + int lsb, w, dc; + + field_access = fields[k].get_access(maps[j]); + dc = (fields[k].get_compare() == UVM_NO_CHECK); + lsb = fields[k].get_lsb_pos(); + w = fields[k].get_n_bits(); + // Ignore Write-only fields because + // you are not supposed to read them + case (field_access) + "WO", "WOC", "WOS", "WO1", "NOACCESS": dc = 1; + endcase + // Any unused bits on the right side of the LSB? + while (next_lsb < lsb) mode[next_lsb++] = "RO"; + + repeat (w) begin + mode[next_lsb] = field_access; + dc_mask[next_lsb] = dc; + next_lsb++; + end + end + // Any unused bits on the left side of the MSB? + while (next_lsb < `UVM_REG_DATA_WIDTH) + mode[next_lsb++] = "RO"; + + `uvm_info("uvm_reg_bit_bash_seq", $sformatf("Verifying bits in register %s in map \"%s\"...", + rg.get_full_name(), maps[j].get_full_name()),UVM_LOW) + + // Bash the kth bit + for (int k = 0; k < n_bits; k++) begin + // Cannot test unpredictable bit behavior + if (dc_mask[k]) continue; + + bash_kth_bit(rg, k, mode[k], maps[j], dc_mask); + end + + end + endtask: body + + + task bash_kth_bit(uvm_reg rg, + int k, + string mode, + uvm_reg_map map, + uvm_reg_data_t dc_mask); + uvm_status_e status; + uvm_reg_data_t val, exp, v; + bit bit_val; + + `uvm_info("uvm_reg_bit_bash_seq", $sformatf("...Bashing %s bit #%0d", mode, k),UVM_HIGH) + + repeat (2) begin + val = rg.get(); + v = val; + exp = val; + val[k] = ~val[k]; + bit_val = val[k]; + + rg.write(status, val, UVM_FRONTDOOR, map, this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_bit_bash_seq", $sformatf("Status was %s when writing to register \"%s\" through map \"%s\".", + status.name(), rg.get_full_name(), map.get_full_name())) + end + + exp = rg.get() & ~dc_mask; + rg.read(status, val, UVM_FRONTDOOR, map, this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_bit_bash_seq", $sformatf("Status was %s when reading register \"%s\" through map \"%s\".", + status.name(), rg.get_full_name(), map.get_full_name())) + end + + val &= ~dc_mask; + if (val !== exp) begin + `uvm_error("uvm_reg_bit_bash_seq", $sformatf("Writing a %b in bit #%0d of register \"%s\" with initial value 'h%h yielded 'h%h instead of 'h%h", + bit_val, k, rg.get_full_name(), v, val, exp)) + end + end + endtask: bash_kth_bit + +endclass: uvm_reg_single_bit_bash_seq + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_bit_bash_seq +// +// +// Verify the implementation of all registers in a block +// by executing the sequence on it. +// +// If bit-type resource named +// "NO_REG_TESTS" or "NO_REG_BIT_BASH_TEST" +// in the "REG::" namespace +// matches the full name of the block, +// the block is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"}, +//| "NO_REG_TESTS", 1, this); +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.2.2.1 +class uvm_reg_bit_bash_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- model + // + // The block to be tested. Declared in the base class. + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- reg_seq + // + // The sequence used to test one register + // + protected uvm_reg_single_bit_bash_seq reg_seq; + + `uvm_object_utils(uvm_reg_bit_bash_seq) + + // @uvm-ieee 1800.2-2017 auto E.2.2.3.1 + function new(string name="uvm_reg_bit_bash_seq"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto E.2.2.3.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_reg_bit_bash_seq", "No register model specified to run sequence on") + return; + end + + uvm_report_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + +`ifdef VERILATOR + reg_seq = uvm_reg_single_bit_bash_seq::type_id_create("reg_single_bit_bash_seq"); +`else + reg_seq = uvm_reg_single_bit_bash_seq::type_id::create("reg_single_bit_bash_seq"); +`endif + + this.reset_blk(model); + model.reset(); + + do_block(model); + endtask + + + // Task -- NODOCS -- do_block + // + // Test all of the registers in a given ~block~ + // + protected virtual task do_block(uvm_reg_block blk); + uvm_reg regs[$]; + + if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_BIT_BASH_TEST", 0) != null ) + return; + + // Iterate over all registers, checking accesses + blk.get_registers(regs, UVM_NO_HIER); + foreach (regs[i]) begin + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()}, + "NO_REG_BIT_BASH_TEST", 0) != null ) + continue; + + reg_seq.rg = regs[i]; + reg_seq.start(null,this); + end + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks,UVM_NO_HIER); + foreach (blks[i]) begin + do_block(blks[i]); + end + end + endtask: do_block + + + // Task -- NODOCS -- reset_blk + // + // Reset the DUT that corresponds to the specified block abstraction class. + // + // Currently empty. + // Will rollback the environment's phase to the ~reset~ + // phase once the new phasing is available. + // + // In the meantime, the DUT should be reset before executing this + // test sequence or this method should be implemented + // in an extension to reset the DUT. + // + virtual task reset_blk(uvm_reg_block blk); + endtask + +endclass: uvm_reg_bit_bash_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_reg_hw_reset_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_reg_hw_reset_seq.svh new file mode 100644 index 0000000000..376ca35e5c --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_reg_hw_reset_seq.svh @@ -0,0 +1,187 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2012 Semifore +// Copyright 2018 Qualcomm, Inc. +// Copyright 2004-2013 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + +// +// class -- NODOCS -- uvm_reg_hw_reset_seq +// Test the hard reset values of registers +// +// The test sequence performs the following steps +// +// 1. resets the DUT and the +// block abstraction class associated with this sequence. +// +// 2. reads all of the registers in the block, +// via all of the available address maps, +// comparing the value read with the expected reset value. +// +// If bit-type resource named +// "NO_REG_TESTS" or "NO_REG_HW_RESET_TEST" +// in the "REG::" namespace +// matches the full name of the block or register, +// the block or register is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"}, +//| "NO_REG_TESTS", 1, this); +// +// This is usually the first test executed on any DUT. +// + +// @uvm-ieee 1800.2-2017 auto E.1.1 +class uvm_reg_hw_reset_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + `uvm_object_utils(uvm_reg_hw_reset_seq) + + // @uvm-ieee 1800.2-2017 auto E.1.2.1.1 + function new(string name="uvm_reg_hw_reset_seq"); + super.new(name); + endfunction + + + // Variable -- NODOCS -- model + // + // The block to be tested. Declared in the base class. + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- body + // + // Executes the Hardware Reset sequence. + // Do not call directly. Use seq.start() instead. + + // @uvm-ieee 1800.2-2017 auto E.1.2.1.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_reg_hw_reset_seq", "Not block or system specified to run sequence on") + return; + end + `uvm_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW) + + this.reset_blk(model); + model.reset(); + + do_block(model); + endtask: body + +// Task -- NODOCS -- do_block + // + // Test all of the registers in a given ~block~ + // + protected virtual task do_block(uvm_reg_block blk); + uvm_reg_map maps[$]; + uvm_reg_map sub_maps[$]; + uvm_reg regs[$]; + + if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_HW_RESET_TEST", 0) != null ) begin + return; + + end + + blk.get_registers(regs, UVM_NO_HIER); + + foreach(regs[ridx]) begin + if (uvm_resource_db#(bit)::get_by_name({"REG::",regs[ridx].get_full_name()}, + "NO_REG_TESTS", 0) != null || + regs[ridx].has_reset() == 0 || + uvm_resource_db#(bit)::get_by_name({"REG::",regs[ridx].get_full_name()}, + "NO_REG_HW_RESET_TEST", 0) != null ) + continue; + + begin + uvm_reg_map rm[$]; + uvm_status_e status; + uvm_reg_field fields[$]; + uvm_check_e field_check_restore[uvm_reg_field]; + + regs[ridx].get_maps(rm); + + regs[ridx].get_fields(fields); + + foreach(fields[fidx]) begin + if (fields[fidx].has_reset() == 0 || + fields[fidx].get_compare() == UVM_NO_CHECK || + uvm_resource_db#(bit)::get_by_name({"REG::",fields[fidx].get_full_name()}, + "NO_REG_HW_RESET_TEST", 0) != null) begin + field_check_restore[fields[fidx]] = fields[fidx].get_compare(); + fields[fidx].set_compare(UVM_NO_CHECK); + end + end + // if there are some fields to check + if(fields.size() != field_check_restore.size()) begin + foreach(rm[midx]) begin + `uvm_info(get_type_name(), + $sformatf("Verifying reset value of register %s in map \"%s\"...", + regs[ridx].get_full_name(), rm[midx].get_full_name()), UVM_LOW) + + regs[ridx].mirror(status, UVM_CHECK, UVM_FRONTDOOR, rm[midx], this); + + if (status != UVM_IS_OK) begin + `uvm_error(get_type_name(), + $sformatf("Status was %s when reading reset value of register \"%s\" through map \"%s\".", + status.name(), regs[ridx].get_full_name(), rm[midx].get_full_name())) + end + end + end + // restore compare setting + foreach(field_check_restore[field]) begin + field.set_compare(field_check_restore[field]); + end + end + end + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i]); + end + end + + endtask:do_block + + + // + // task -- NODOCS -- reset_blk + // Reset the DUT that corresponds to the specified block abstraction class. + // + // Currently empty. + // Will rollback the environment's phase to the ~reset~ + // phase once the new phasing is available. + // + // In the meantime, the DUT should be reset before executing this + // test sequence or this method should be implemented + // in an extension to reset the DUT. + // + virtual task reset_blk(uvm_reg_block blk); + endtask + +endclass: uvm_reg_hw_reset_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_built_in_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_built_in_seq.svh new file mode 100644 index 0000000000..59d610e5f8 --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_built_in_seq.svh @@ -0,0 +1,167 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2015-2018 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. +// ------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_mem_built_in_seq +// +// Sequence that executes a user-defined selection +// of pre-defined register and memory test sequences. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.8.1 +class uvm_reg_mem_built_in_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + `uvm_object_utils(uvm_reg_mem_built_in_seq) + + // @uvm-ieee 1800.2-2017 auto E.8.3.1 + function new(string name="uvm_reg_mem_built_in_seq"); + super.new(name); + endfunction + + // Variable -- NODOCS -- model + // + // The block to be tested. Declared in the base class. + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- tests + // + // The pre-defined test sequences to be executed. + // + bit [63:0] tests = UVM_DO_ALL_REG_MEM_TESTS; + + + // Task -- NODOCS -- body + // + // Executes any or all the built-in register and memory sequences. + // Do not call directly. Use seq.start() instead. + + // @uvm-ieee 1800.2-2017 auto E.8.3.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_reg_mem_built_in_seq", "Not block or system specified to run sequence on") + return; + end + + uvm_report_info("START_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + + if (tests & UVM_DO_REG_HW_RESET && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_HW_RESET_TEST", 0) == null ) begin +`ifdef VERILATOR + uvm_reg_hw_reset_seq seq = uvm_reg_hw_reset_seq::type_id_create("reg_hw_reset_seq"); +`else + uvm_reg_hw_reset_seq seq = uvm_reg_hw_reset_seq::type_id::create("reg_hw_reset_seq"); +`endif + seq.model = model; + seq.start(null,this); + `uvm_info("FINISH_SEQ",{"Finished ",seq.get_name()," sequence."},UVM_LOW) + end + + if (tests & UVM_DO_REG_BIT_BASH && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_BIT_BASH_TEST", 0) == null ) begin +`ifdef VERILATOR + uvm_reg_bit_bash_seq seq = uvm_reg_bit_bash_seq::type_id_create("reg_bit_bash_seq"); +`else + uvm_reg_bit_bash_seq seq = uvm_reg_bit_bash_seq::type_id::create("reg_bit_bash_seq"); +`endif + seq.model = model; + seq.start(null,this); + `uvm_info("FINISH_SEQ",{"Finished ",seq.get_name()," sequence."},UVM_LOW) + end + + if (tests & UVM_DO_REG_ACCESS && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_ACCESS_TEST", 0) == null ) begin +`ifdef VERILATOR + uvm_reg_access_seq seq = uvm_reg_access_seq::type_id_create("reg_access_seq"); +`else + uvm_reg_access_seq seq = uvm_reg_access_seq::type_id::create("reg_access_seq"); +`endif + seq.model = model; + seq.start(null,this); + `uvm_info("FINISH_SEQ",{"Finished ",seq.get_name()," sequence."},UVM_LOW) + end + + if (tests & UVM_DO_MEM_ACCESS && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_MEM_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_MEM_ACCESS_TEST", 0) == null ) begin +`ifdef VERILATOR + uvm_mem_access_seq seq = uvm_mem_access_seq::type_id_create("mem_access_seq"); +`else + uvm_mem_access_seq seq = uvm_mem_access_seq::type_id::create("mem_access_seq"); +`endif + seq.model = model; + seq.start(null,this); + `uvm_info("FINISH_SEQ",{"Finished ",seq.get_name()," sequence."},UVM_LOW) + end + + if (tests & UVM_DO_SHARED_ACCESS && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_SHARED_ACCESS_TEST", 0) == null ) begin +`ifdef VERILATOR + uvm_reg_mem_shared_access_seq seq = uvm_reg_mem_shared_access_seq::type_id_create("shared_access_seq"); +`else + uvm_reg_mem_shared_access_seq seq = uvm_reg_mem_shared_access_seq::type_id::create("shared_access_seq"); +`endif + seq.model = model; + seq.start(null,this); + `uvm_info("FINISH_SEQ",{"Finished ",seq.get_name()," sequence."},UVM_LOW) + end + + if (tests & UVM_DO_MEM_WALK && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_REG_TESTS", 0) == null && + uvm_resource_db#(bit)::get_by_name({"REG::",model.get_full_name()}, + "NO_MEM_WALK_TEST", 0) == null ) begin +`ifdef VERILATOR + uvm_mem_walk_seq seq = uvm_mem_walk_seq::type_id_create("mem_walk_seq"); +`else + uvm_mem_walk_seq seq = uvm_mem_walk_seq::type_id::create("mem_walk_seq"); +`endif + seq.model = model; + seq.start(null,this); + `uvm_info("FINISH_SEQ",{"Finished ",seq.get_name()," sequence."},UVM_LOW) + end + + endtask: body + +endclass: uvm_reg_mem_built_in_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh new file mode 100644 index 0000000000..06fd7983c0 --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh @@ -0,0 +1,178 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +// ------------------------------------------------------------- +// + +// +// TITLE -- NODOCS -- HDL Paths Checking Test Sequence +// + +// +// class -- NODOCS -- uvm_reg_mem_hdl_paths_seq +// +// Verify the correctness of HDL paths specified for registers and memories. +// +// This sequence is be used to check that the specified backdoor paths +// are indeed accessible by the simulator. +// By default, the check is performed for the default design abstraction. +// If the simulation contains multiple models of the DUT, +// HDL paths for multiple design abstractions can be checked. +// +// If a path is not accessible by the simulator, it cannot be used for +// read/write backdoor accesses. In that case a warning is produced. +// A simulator may have finer-grained access permissions such as separate +// read or write permissions. +// These extra access permissions are NOT checked. +// +// The test is performed in zero time and +// does not require any reads/writes to/from the DUT. +// + +// @uvm-ieee 1800.2-2017 auto E.7.1 +class uvm_reg_mem_hdl_paths_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + // Variable -- NODOCS -- abstractions + // If set, check the HDL paths for the specified design abstractions. + // If empty, check the HDL path for the default design abstraction, + // as specified with + string abstractions[$]; + + `uvm_object_utils_begin(uvm_reg_mem_hdl_paths_seq) + `uvm_field_queue_string(abstractions, UVM_DEFAULT) + `uvm_object_utils_end + + // @uvm-ieee 1800.2-2017 auto E.7.3 + function new(string name="uvm_reg_mem_hdl_paths_seq"); + super.new(name); + endfunction + + virtual task body(); + + if (model == null) begin + uvm_report_error("uvm_reg_mem_hdl_paths_seq", "Register model handle is null"); + return; + end + + `uvm_info("uvm_reg_mem_hdl_paths_seq", + {"checking HDL paths for all registers/memories in ", + model.get_full_name()}, UVM_LOW) + + if (abstractions.size() == 0) + do_block(model, ""); + else begin + foreach (abstractions[i]) + do_block(model, abstractions[i]); + end + + `uvm_info("uvm_reg_mem_hdl_paths_seq", "HDL path validation completed ",UVM_LOW) + + endtask: body + + + // Any additional steps required to reset the block + // and make it accessible + virtual task reset_blk(uvm_reg_block blk); + endtask + + + protected virtual function void do_block(uvm_reg_block blk, + string kind); + uvm_reg regs[$]; + uvm_mem mems[$]; + + `uvm_info("uvm_reg_mem_hdl_paths_seq", + {"Validating HDL paths in ", blk.get_full_name(), + " for ", (kind == "") ? "default" : kind, + " design abstraction"}, UVM_MEDIUM) + + // Iterate over all registers, checking accesses + blk.get_registers(regs, UVM_NO_HIER); + foreach (regs[i]) + check_reg(regs[i], kind); + + blk.get_memories(mems, UVM_NO_HIER); + foreach (mems[i]) + check_mem(mems[i], kind); + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i], kind); + end + end + endfunction: do_block + + + protected virtual function void check_reg(uvm_reg r, + string kind); + uvm_hdl_path_concat paths[$]; + + // avoid calling get_full_hdl_path when the register has not path for this abstraction kind + if(!r.has_hdl_path(kind)) + return; + + r.get_full_hdl_path(paths, kind); + if (paths.size() == 0) return; + + foreach(paths[p]) begin + uvm_hdl_path_concat path=paths[p]; + foreach (path.slices[j]) begin + string p_ = path.slices[j].path; + uvm_reg_data_t d; + if (!uvm_hdl_read(p_,d)) + `uvm_error("uvm_reg_mem_hdl_paths_seq", + $sformatf("HDL path \"%s\" for register \"%s\" is not readable", + p_, r.get_full_name())) + if (!uvm_hdl_check_path(p_)) + `uvm_error("uvm_reg_mem_hdl_paths_seq", + $sformatf("HDL path \"%s\" for register \"%s\" is not accessible", + p_, r.get_full_name())) + end + end + endfunction + + + protected virtual function void check_mem(uvm_mem m, + string kind); + uvm_hdl_path_concat paths[$]; + + // avoid calling get_full_hdl_path when the register has not path for this abstraction kind + if(!m.has_hdl_path(kind)) + return; + + m.get_full_hdl_path(paths, kind); + if (paths.size() == 0) return; + + foreach(paths[p]) begin + uvm_hdl_path_concat path=paths[p]; + foreach (path.slices[j]) + begin + string p_ = path.slices[j].path; + if(!uvm_hdl_check_path(p_)) + `uvm_error("uvm_reg_mem_hdl_paths_seq", + $sformatf("HDL path \"%s\" for memory \"%s\" is not accessible", + p_, m.get_full_name())) + end + end + endfunction +endclass: uvm_reg_mem_hdl_paths_seq diff --git a/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_shared_access_seq.svh b/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_shared_access_seq.svh new file mode 100644 index 0000000000..1b730a7349 --- /dev/null +++ b/test_regress/t/t_uvm/reg/sequences/uvm_reg_mem_shared_access_seq.svh @@ -0,0 +1,496 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2015-2018 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. +// ------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Shared Register and Memory Access Test Sequences +//------------------------------------------------------------------------------ +// This section defines sequences for testing registers and memories that are +// shared between two or more physical interfaces, i.e. are associated with +// more than one instance. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_shared_access_seq +// +// Verify the accessibility of a shared register +// by writing through each address map +// then reading it via every other address maps +// in which the register is readable and the backdoor, +// making sure that the resulting value matches the mirrored value. +// +// If bit-type resource named +// "NO_REG_TESTS" or "NO_REG_SHARED_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the register, +// the register is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.r0.get_full_name()}, +//| "NO_REG_TESTS", 1, this); +// +// Registers that contain fields with unknown access policies +// cannot be tested. +// +// The DUT should be idle and not modify any register during this test. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.4.1.1 +class uvm_reg_shared_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- rg + // The register to be tested + uvm_reg rg; + + `uvm_object_utils(uvm_reg_shared_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.4.1.3 + function new(string name="uvm_reg_shared_access_seq"); + super.new(name); + endfunction + + + virtual task body(); + uvm_reg_data_t other_mask; + uvm_reg_data_t wo_mask[$]; + uvm_reg_field fields[$]; + uvm_reg_map maps[$]; + + if (rg == null) begin + `uvm_error("uvm_reg_shared_access_seq", "No register specified to run sequence on") + return; + end + + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",rg.get_full_name()}, + "NO_REG_SHARED_ACCESS_TEST", 0) != null ) + return; + + // Only look at shared registers + if (rg.get_n_maps() < 2) return; + rg.get_maps(maps); + + // Let's see what kind of bits we have... + rg.get_fields(fields); + + // Identify unpredictable bits and the ones we shouldn't change + other_mask = 0; + foreach (fields[k]) begin + int lsb, w; + + lsb = fields[k].get_lsb_pos(); + w = fields[k].get_n_bits(); + + if (!fields[k].is_known_access(maps[0])) begin + repeat (w) begin + other_mask[lsb++] = 1'b1; + end + end + end + + // WO bits will always readback as 0's but the mirror + // with return what is supposed to have been written + // so we cannot use the mirror-check function + foreach (maps[j]) begin + uvm_reg_data_t wo; + wo = 0; + foreach (fields[k]) begin + int lsb, w; + + lsb = fields[k].get_lsb_pos(); + w = fields[k].get_n_bits(); + + if (fields[k].get_access(maps[j]) == "WO") begin + repeat (w) begin + wo[lsb++] = 1'b1; + end + end + end + wo_mask[j] = wo; + end + + // Try to write through each map + foreach (maps[j]) begin + uvm_status_e status; + uvm_reg_data_t prev, v; + + // The mirror should contain the initial value + prev = rg.get(); + + // Write a random value, except in those "don't touch" fields + v = ({$random, $random} & ~other_mask) | (prev & other_mask); + + `uvm_info("uvm_reg_shared_access_seq", $sformatf("Writing register %s via map \"%s\"...", + rg.get_full_name(), maps[j].get_full_name), UVM_LOW) + + `uvm_info("uvm_reg_shared_access_seq", $sformatf("Writing 'h%h over 'h%h", v, prev),UVM_DEBUG) + + rg.write(status, v, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_shared_access_seq", $sformatf("Status was %s when writing register \"%s\" through map \"%s\".", + status.name(), rg.get_full_name(), maps[j].get_full_name())) + end + + foreach (maps[k]) begin + uvm_reg_data_t actual, exp; + + `uvm_info("uvm_reg_shared_access_seq", $sformatf("Reading register %s via map \"%s\"...", + rg.get_full_name(), maps[k].get_full_name()), UVM_LOW) + + // Was it what we expected? + exp = rg.get() & ~wo_mask[k]; + + rg.read(status, actual, UVM_FRONTDOOR, maps[k], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_reg_shared_access_seq", $sformatf("Status was %s when reading register \"%s\" through map \"%s\".", + status.name(), rg.get_full_name(), maps[k].get_full_name())) + end + + `uvm_info("uvm_reg_shared_access_seq", $sformatf("Read 'h%h, expecting 'h%h", + actual, exp),UVM_DEBUG) + + if (actual !== exp) begin + `uvm_error("uvm_reg_shared_access_seq", $sformatf("Register \"%s\" through map \"%s\" is 'h%h instead of 'h%h after writing 'h%h via map \"%s\" over 'h%h.", + rg.get_full_name(), maps[k].get_full_name(), + actual, exp, v, maps[j].get_full_name(), prev)) + end + end + end + endtask: body +endclass: uvm_reg_shared_access_seq + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_mem_shared_access_seq +//------------------------------------------------------------------------------ +// +// Verify the accessibility of a shared memory +// by writing through each address map +// then reading it via every other address maps +// in which the memory is readable and the backdoor, +// making sure that the resulting value matches the written value. +// +// If bit-type resource named +// "NO_REG_TESTS", "NO_MEM_TESTS", +// "NO_REG_SHARED_ACCESS_TEST" or "NO_MEM_SHARED_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the memory, +// the memory is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.mem0.get_full_name()}, +//| "NO_MEM_TESTS", 1, this); +// +// The DUT should be idle and not modify the memory during this test. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.4.2.1 +class uvm_mem_shared_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // variable -- NODOCS -- mem + // The memory to be tested + uvm_mem mem; + + `uvm_object_utils(uvm_mem_shared_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.4.2.3 + function new(string name="uvm_mem_shared_access_seq"); + super.new(name); + endfunction + + virtual task body(); + int read_from; + uvm_reg_map maps[$]; + + if (mem == null) begin + `uvm_error("uvm_mem_shared_access_seq", "No memory specified to run sequence on") + return; + end + + // Memories with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_REG_SHARED_ACCESS_TEST", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()}, + "NO_MEM_SHARED_ACCESS_TEST", 0) != null ) + return; + + // Only look at shared memories + if (mem.get_n_maps() < 2) return; + mem.get_maps(maps); + + // We need at least a backdoor or a map that can read + // the shared memory + read_from = -1; + if (mem.get_backdoor() == null) begin + foreach (maps[j]) begin + string right; + right = mem.get_access(maps[j]); + if (right == "RW" || + right == "RO") begin + read_from = j; + break; + end + end + if (read_from < 0) begin + `uvm_warning("uvm_mem_shared_access_seq", $sformatf("Memory \"%s\" cannot be read from any maps or backdoor. Shared access not verified.", mem.get_full_name())) + return; + end + end + + // Try to write through each map + foreach (maps[j]) begin + + `uvm_info("uvm_mem_shared_access_seq", $sformatf("Writing shared memory \"%s\" via map \"%s\".", + mem.get_full_name(), maps[j].get_full_name()), UVM_LOW) + + // All addresses + for (int offset = 0; offset < mem.get_size(); offset++) begin + uvm_status_e status; + uvm_reg_data_t prev, v; + + // Read the initial value + if (mem.get_backdoor() != null) begin + mem.peek(status, offset, prev); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_shared_access_seq", $sformatf("Status was %s when reading initial value of \"%s\"[%0d] through backdoor.", + status.name(), mem.get_full_name(), offset)) + end + end + else begin + mem.read(status, offset, prev, UVM_FRONTDOOR, maps[read_from], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_shared_access_seq", $sformatf("Status was %s when reading initial value of \"%s\"[%0d] through map \"%s\".", + status.name(), mem.get_full_name(), + offset, maps[read_from].get_full_name())) + end + end + + + // Write a random value, + v = {$random, $random}; + + mem.write(status, offset, v, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_shared_access_seq", $sformatf("Status was %s when writing \"%s\"[%0d] through map \"%s\".", + status.name(), mem.get_full_name(), offset, maps[j].get_full_name())) + end + + // Read back from all other maps + foreach (maps[k]) begin + uvm_reg_data_t actual, exp; + + mem.read(status, offset, actual, UVM_FRONTDOOR, maps[k], this); + if (status != UVM_IS_OK) begin + `uvm_error("uvm_mem_shared_access_seq", $sformatf("Status was %s when reading %s[%0d] through map \"%s\".", + status.name(), mem.get_full_name(), offset, maps[k].get_full_name())) + end + + // Was it what we expected? + exp = v; + if (mem.get_access(maps[j]) == "RO") begin + exp = prev; + end + if (mem.get_access(maps[k]) == "WO") begin + exp = 0; + end + // Trim to number of bits + exp &= (1 << mem.get_n_bits()) - 1; + if (actual !== exp) begin + `uvm_error("uvm_mem_shared_access_seq", $sformatf("%s[%0d] through map \"%s\" is 'h%h instead of 'h%h after writing 'h%h via map \"%s\" over 'h%h.", + mem.get_full_name(), offset, maps[k].get_full_name(), + actual, exp, v, maps[j].get_full_name(), prev)) + end + end + end + end + endtask: body +endclass: uvm_mem_shared_access_seq + + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_mem_shared_access_seq +//------------------------------------------------------------------------------ +// +// Verify the accessibility of all shared registers +// and memories in a block +// by executing the +// and +// sequence respectively on every register and memory within it. +// +// If bit-type resource named +// "NO_REG_TESTS", "NO_MEM_TESTS", +// "NO_REG_SHARED_ACCESS_TEST" or "NO_MEM_SHARED_ACCESS_TEST" +// in the "REG::" namespace +// matches the full name of the block, +// the block is not tested. +// +//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"}, +//| "NO_REG_TESTS", 1, this); +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto E.4.3.1 +class uvm_reg_mem_shared_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); + + // Variable -- NODOCS -- model + // + // The block to be tested + // + //| uvm_reg_block model; + + + // Variable -- NODOCS -- reg_seq + // + // The sequence used to test one register + // + protected uvm_reg_shared_access_seq reg_seq; + + + // Variable -- NODOCS -- mem_seq + // + // The sequence used to test one memory + // + protected uvm_mem_shared_access_seq mem_seq; + + `uvm_object_utils(uvm_reg_mem_shared_access_seq) + + // @uvm-ieee 1800.2-2017 auto E.4.3.3.1 + function new(string name="uvm_reg_mem_shared_access_seq"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto E.4.3.3.2 + virtual task body(); + + if (model == null) begin + `uvm_error("uvm_reg_mem_shared_access_seq", "No register model specified to run sequence on") + return; + end + + uvm_report_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW); + +`ifdef VERILATOR + reg_seq = uvm_reg_shared_access_seq::type_id_create("reg_shared_access_seq"); + mem_seq = uvm_mem_shared_access_seq::type_id_create("reg_shared_access_seq"); +`else + reg_seq = uvm_reg_shared_access_seq::type_id::create("reg_shared_access_seq"); + mem_seq = uvm_mem_shared_access_seq::type_id::create("reg_shared_access_seq"); +`endif + + this.reset_blk(model); + model.reset(); + + do_block(model); + endtask: body + + + // Task -- NODOCS -- do_block + // + // Test all of the registers and memories in a block + // + protected virtual task do_block(uvm_reg_block blk); + uvm_reg regs[$]; + uvm_mem mems[$]; + + if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_REG_SHARED_ACCESS_TEST", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()}, + "NO_MEM_SHARED_ACCESS_TEST", 0) != null ) + return; + + this.reset_blk(model); + model.reset(); + + // Iterate over all registers, checking accesses + blk.get_registers(regs, UVM_NO_HIER); + foreach (regs[i]) begin + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",regs[i].get_full_name()}, + "NO_REG_SHARED_ACCESS_TEST", 0) != null ) + continue; + reg_seq.rg = regs[i]; + reg_seq.start(this.get_sequencer(), this); + end + + // Iterate over all memories, checking accesses + blk.get_memories(mems, UVM_NO_HIER); + foreach (mems[i]) begin + // Registers with some attributes are not to be tested + if (uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_REG_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_MEM_TESTS", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_REG_SHARED_ACCESS_TEST", 0) != null || + uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()}, + "NO_MEM_SHARED_ACCESS_TEST", 0) != null ) + continue; + mem_seq.mem = mems[i]; + mem_seq.start(this.get_sequencer(), this); + end + + begin + uvm_reg_block blks[$]; + + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i]); + end + end + endtask: do_block + + + // + // task -- NODOCS -- reset_blk + // Reset the DUT that corresponds to the specified block abstraction class. + // + // Currently empty. + // Will rollback the environment's phase to the ~reset~ + // phase once the new phasing is available. + // + // In the meantime, the DUT should be reset before executing this + // test sequence or this method should be implemented + // in an extension to reset the DUT. + // + virtual task reset_blk(uvm_reg_block blk); + endtask + + +endclass: uvm_reg_mem_shared_access_seq diff --git a/test_regress/t/t_uvm/reg/uvm_mem.svh b/test_regress/t/t_uvm/reg/uvm_mem.svh new file mode 100644 index 0000000000..8f70f61d32 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_mem.svh @@ -0,0 +1,2033 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2018 Intel Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// 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_mem +//------------------------------------------------------------------------------ +// Memory abstraction base class +// +// A memory is a collection of contiguous locations. +// A memory may be accessible via more than one address map. +// +// Unlike registers, memories are not mirrored because of the potentially +// large data space: tests that walk the entire memory space would negate +// any benefit from sparse memory modelling techniques. +// Rather than relying on a mirror, it is recommended that +// backdoor access be used instead. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.6.1 +class uvm_mem extends uvm_object; +// See Mantis 6040. I did NOT make this class virtual because it +// seems to break a lot of existing tests and code. +// Sought LRM clarification + + typedef enum {UNKNOWNS, ZEROES, ONES, ADDRESS, VALUE, INCR, DECR} init_e; + + local bit m_locked; + local bit m_read_in_progress; + local bit m_write_in_progress; + local string m_access; + local longint unsigned m_size; + local uvm_reg_block m_parent; + local bit m_maps[uvm_reg_map]; + local int unsigned m_n_bits; + local uvm_reg_backdoor m_backdoor; + local bit m_is_powered_down; + local int m_has_cover; + local int m_cover_on; + local string m_fname; + local int m_lineno; + local bit m_vregs[uvm_vreg]; + local uvm_object_string_pool + #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; + + local static int unsigned m_max_size; + + //---------------------- + // Group -- NODOCS -- Initialization + //---------------------- + + + // @uvm-ieee 1800.2-2017 auto 18.6.3.1 + extern function new (string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.3.2 + extern function void configure (uvm_reg_block parent, + string hdl_path = ""); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.3.3 + extern virtual function void set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + + + /*local*/ extern virtual function void set_parent(uvm_reg_block parent); + /*local*/ extern function void add_map(uvm_reg_map map); + /*local*/ extern function void Xlock_modelX(); + /*local*/ extern function void Xadd_vregX(uvm_vreg vreg); + /*local*/ extern function void Xdelete_vregX(uvm_vreg vreg); + + + // variable -- NODOCS -- mam + // + // Memory allocation manager + // + // Memory allocation manager for the memory corresponding to this + // abstraction class instance. + // Can be used to allocate regions of consecutive addresses of + // specific sizes, such as DMA buffers, + // or to locate virtual register array. + // + uvm_mem_mam mam; + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // Function -- NODOCS -- get_name + // + // Get the simple name + // + // Return the simple object name of this memory. + // + + // Function -- NODOCS -- get_full_name + // + // Get the hierarchical name + // + // Return the hierarchal name of this memory. + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.1 + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.2 + extern virtual function int get_n_maps (); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.3 + extern function bit is_in_map (uvm_reg_map map); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.4 + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + + + /*local*/ extern function uvm_reg_map get_local_map (uvm_reg_map map); + + /*local*/ extern function uvm_reg_map get_default_map (); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.5 + extern virtual function string get_rights (uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.6 + extern virtual function string get_access(uvm_reg_map map = null); + + + // Function -- NODOCS -- get_size + // + // Returns the number of unique memory locations in this memory. + // this is in units of the memory declaration: full memory is get_size()*get_n_bits() (bits) + extern function longint unsigned get_size(); + + + // Function -- NODOCS -- get_n_bytes + // + // Return the width, in number of bytes, of each memory location + // + extern function int unsigned get_n_bytes(); + + + // Function -- NODOCS -- get_n_bits + // + // Returns the width, in number of bits, of each memory location + // + extern function int unsigned get_n_bits(); + + + // Function -- NODOCS -- get_max_size + // + // Returns the maximum width, in number of bits, of all memories + // + extern static function int unsigned get_max_size(); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.11 + extern virtual function void get_virtual_registers(ref uvm_vreg regs[$]); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.12 + extern virtual function void get_virtual_fields(ref uvm_vreg_field fields[$]); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.13 + extern virtual function uvm_vreg get_vreg_by_name(string name); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.14 + extern virtual function uvm_vreg_field get_vfield_by_name(string name); + + + // Function -- NODOCS -- get_vreg_by_offset + // + // Find the virtual register implemented at the specified offset + // + // Finds the virtual register implemented in this memory + // at the specified ~offset~ in the specified address ~map~ + // and returns its abstraction class instance. + // If no virtual register at the offset is found, returns ~null~. + // + extern virtual function uvm_vreg get_vreg_by_offset(uvm_reg_addr_t offset, + uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.15 + extern virtual function uvm_reg_addr_t get_offset (uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.16 + extern virtual function uvm_reg_addr_t get_address(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.4.17 + extern virtual function int get_addresses(uvm_reg_addr_t offset = 0, + uvm_reg_map map=null, + ref uvm_reg_addr_t addr[]); + + + //------------------ + // Group -- NODOCS -- HDL Access + //------------------ + + + // @uvm-ieee 1800.2-2017 auto 18.6.5.1 + extern virtual task write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.5.2 + extern virtual task read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.5.3 + extern virtual task burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.5.4 + extern virtual task burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + ref uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.5.5 + extern virtual task poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.5.6 + extern virtual task peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + extern protected function bit Xcheck_accessX (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + + + extern virtual task do_write (uvm_reg_item rw); + extern virtual task do_read (uvm_reg_item rw); + + + //----------------- + // Group -- NODOCS -- Frontdoor + //----------------- + + + // @uvm-ieee 1800.2-2017 auto 18.6.6.2 + extern function void set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.6.1 + extern function uvm_reg_frontdoor get_frontdoor(uvm_reg_map map = null); + + + //---------------- + // Group -- NODOCS -- Backdoor + //---------------- + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.2 + extern function void set_backdoor (uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.1 + extern function uvm_reg_backdoor get_backdoor(bit inherited = 1); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.3 + extern function void clear_hdl_path (string kind = "RTL"); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.4 + extern function void add_hdl_path (uvm_hdl_path_slice slices[], + string kind = "RTL"); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.5 + extern function void add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.6 + extern function bit has_hdl_path (string kind = ""); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.7 + extern function void get_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = ""); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.9 + extern function void get_full_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = "", + input string separator = "."); + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.8 + extern function void get_hdl_path_kinds (ref string kinds[$]); + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.10 + extern virtual protected task backdoor_read(uvm_reg_item rw); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.7.11 + extern virtual task backdoor_write(uvm_reg_item rw); + + + + extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw); + + + //----------------- + // Group -- NODOCS -- Callbacks + //----------------- + `uvm_register_cb(uvm_mem, uvm_reg_cbs) + + + + // @uvm-ieee 1800.2-2017 auto 18.6.9.1 + virtual task pre_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.6.9.2 + virtual task post_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.6.9.3 + virtual task pre_read(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.6.9.4 + virtual task post_read(uvm_reg_item rw); endtask + + + //---------------- + // Group -- NODOCS -- Coverage + //---------------- + + + // @uvm-ieee 1800.2-2017 auto 18.6.8.1 + extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.8.2 + extern virtual protected function void add_coverage(uvm_reg_cvr_t models); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.8.3 + extern virtual function bit has_coverage(uvm_reg_cvr_t models); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.8.5 + extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.8.4 + extern virtual function bit get_coverage(uvm_reg_cvr_t is_on); + + + + // @uvm-ieee 1800.2-2017 auto 18.6.8.6 + protected virtual function void sample(uvm_reg_addr_t offset, + bit is_read, + uvm_reg_map map); + endfunction + + /*local*/ function void XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + sample(addr, is_read, map); + endfunction + + // Core ovm_object operations + + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + + +endclass: uvm_mem + + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + + +// new + +function uvm_mem::new (string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + + super.new(name); + m_locked = 0; + if (n_bits == 0) begin + `uvm_error("RegModel", {"Memory '",get_full_name(),"' cannot have 0 bits"}) + n_bits = 1; + end + m_size = size; + m_n_bits = n_bits; + m_backdoor = null; + m_access = access.toupper(); + m_has_cover = has_coverage; + m_hdl_paths_pool = new("hdl_paths"); + + if (n_bits > m_max_size) + m_max_size = n_bits; + +endfunction: new + + +// configure + +function void uvm_mem::configure(uvm_reg_block parent, + string hdl_path=""); + + if (parent == null) + `uvm_fatal("REG/NULL_PARENT","configure: parent argument is null") + + m_parent = parent; + + if (m_access != "RW" && m_access != "RO") begin + `uvm_error("RegModel", {"Memory '",get_full_name(),"' can only be RW or RO"}) + m_access = "RW"; + end + + begin + uvm_mem_mam_cfg cfg = new; + + cfg.n_bytes = ((m_n_bits-1) / 8) + 1; + cfg.start_offset = 0; + cfg.end_offset = m_size-1; + + cfg.mode = uvm_mem_mam::GREEDY; + cfg.locality = uvm_mem_mam::BROAD; + + mam = new(get_full_name(), cfg, this); + end + + m_parent.add_mem(this); + + if (hdl_path != "") add_hdl_path_slice(hdl_path, -1, -1); +endfunction: configure + + +// set_offset + +function void uvm_mem::set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + + uvm_reg_map orig_map = map; + + if (m_maps.num() > 1 && map == null) begin + `uvm_error("RegModel",{"set_offset requires a non-null map when memory '", + get_full_name(),"' belongs to more than one map."}) + return; + end + + map = get_local_map(map); + + if (map == null) + return; + + map.m_set_mem_offset(this, offset, unmapped); +endfunction + + +// add_map + +function void uvm_mem::add_map(uvm_reg_map map); + m_maps[map] = 1; +endfunction + + +// Xlock_modelX + +function void uvm_mem::Xlock_modelX(); + m_locked = 1; +endfunction: Xlock_modelX + + +// get_full_name + +function string uvm_mem::get_full_name(); + if (m_parent == null) + return get_name(); + + return {m_parent.get_full_name(), ".", get_name()}; + +endfunction: get_full_name + + +// get_block + +function uvm_reg_block uvm_mem::get_block(); + return m_parent; +endfunction: get_block + + +// get_n_maps + +function int uvm_mem::get_n_maps(); + return m_maps.num(); +endfunction: get_n_maps + + +// get_maps + +function void uvm_mem::get_maps(ref uvm_reg_map maps[$]); + foreach (m_maps[map]) + maps.push_back(map); +endfunction + + +// is_in_map + +function bit uvm_mem::is_in_map(uvm_reg_map map); + if (m_maps.exists(map)) + return 1; + foreach (m_maps[l]) begin + uvm_reg_map local_map=l; + uvm_reg_map parent_map = local_map.get_parent_map(); + + while (parent_map != null) begin + if (parent_map == map) + return 1; + parent_map = parent_map.get_parent_map(); + end + end + return 0; +endfunction + + +// get_local_map + +function uvm_reg_map uvm_mem::get_local_map(uvm_reg_map map); + if (map == null) + return get_default_map(); + if (m_maps.exists(map)) + return map; + foreach (m_maps[l]) begin + uvm_reg_map local_map = l; + uvm_reg_map parent_map = local_map.get_parent_map(); + + while (parent_map != null) begin + if (parent_map == map) + return local_map; + parent_map = parent_map.get_parent_map(); + end + end + `uvm_warning("RegModel", + {"Memory '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'"}) + return null; +endfunction + + +// get_default_map + +function uvm_reg_map uvm_mem::get_default_map(); + + // if mem is not associated with any may, return ~null~ + if (m_maps.num() == 0) begin + `uvm_warning("RegModel", + {"Memory '",get_full_name(),"' is not registered with any map"}) + return null; + end + + // if only one map, choose that + if (m_maps.num() == 1) begin + void'(m_maps.first(get_default_map)); + end + + // try to choose one based on default_map in parent blocks. + foreach (m_maps[l]) begin + uvm_reg_map map = l; + uvm_reg_block blk = map.get_parent(); + uvm_reg_map default_map = blk.get_default_map(); + if (default_map != null) begin + uvm_reg_map local_map = get_local_map(default_map); + if (local_map != null) + return local_map; + end + end + + // if that fails, choose the first in this mem's maps + + void'(m_maps.first(get_default_map)); + +endfunction + + +// get_access + +function string uvm_mem::get_access(uvm_reg_map map = null); + get_access = m_access; + if (get_n_maps() == 1) return get_access; + + map = get_local_map(map); + if (map == null) return get_access; + + // Is the memory restricted in this map? + case (get_rights(map)) + "RW": + // No restrictions + return get_access; + + "RO": + case (get_access) + "RW", "RO": get_access = "RO"; + + "WO": `uvm_error("RegModel", {"WO memory '",get_full_name(), + "' restricted to RO in map '",map.get_full_name(),"'"}) + + default: `uvm_error("RegModel", {"Memory '",get_full_name(), + "' has invalid access mode, '",get_access,"'"}) + endcase + + "WO": + case (get_access) + "RW", "WO": get_access = "WO"; + + "RO": `uvm_error("RegModel", {"RO memory '",get_full_name(), + "' restricted to WO in map '",map.get_full_name(),"'"}) + + default: `uvm_error("RegModel", {"Memory '",get_full_name(), + "' has invalid access mode, '",get_access,"'"}) + endcase + + default: `uvm_error("RegModel", {"Shared memory '",get_full_name(), + "' is not shared in map '",map.get_full_name(),"'"}) + endcase +endfunction: get_access + + +// get_rights + +function string uvm_mem::get_rights(uvm_reg_map map = null); + + uvm_reg_map_info info; + + // No right restrictions if not shared + if (m_maps.num() <= 1) begin + return "RW"; + end + + map = get_local_map(map); + + if (map == null) + return "RW"; + + info = map.get_mem_map_info(this); + return info.rights; + +endfunction: get_rights + + +// get_offset + +function uvm_reg_addr_t uvm_mem::get_offset(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + + map = get_local_map(map); + + if (map == null) + return -1; + + map_info = map.get_mem_map_info(this); + + if (map_info.unmapped) begin + `uvm_warning("RegModel", {"Memory '",get_name(), + "' is unmapped in map '", + ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}) + return -1; + end + + return map_info.offset; + +endfunction: get_offset + + + +// get_virtual_registers + +function void uvm_mem::get_virtual_registers(ref uvm_vreg regs[$]); + foreach (m_vregs[vreg]) + regs.push_back(vreg); +endfunction + + +// get_virtual_fields + +function void uvm_mem::get_virtual_fields(ref uvm_vreg_field fields[$]); + + foreach (m_vregs[l]) + begin + uvm_vreg vreg = l; + vreg.get_fields(fields); + end +endfunction: get_virtual_fields + + +// get_vfield_by_name + +function uvm_vreg_field uvm_mem::get_vfield_by_name(string name); + // Return first occurrence of vfield matching name + uvm_vreg_field vfields[$]; + + get_virtual_fields(vfields); + + foreach (vfields[i]) + if (vfields[i].get_name() == name) + return vfields[i]; + + `uvm_warning("RegModel", {"Unable to find virtual field '",name, + "' in memory '",get_full_name(),"'"}) + return null; +endfunction: get_vfield_by_name + + +// get_vreg_by_name + +function uvm_vreg uvm_mem::get_vreg_by_name(string name); + + foreach (m_vregs[l]) + begin + uvm_vreg vreg = l; + if (vreg.get_name() == name) + return vreg; + end + + `uvm_warning("RegModel", {"Unable to find virtual register '",name, + "' in memory '",get_full_name(),"'"}) + return null; + +endfunction: get_vreg_by_name + + +// get_vreg_by_offset + +function uvm_vreg uvm_mem::get_vreg_by_offset(uvm_reg_addr_t offset, + uvm_reg_map map = null); + `uvm_error("RegModel", "uvm_mem::get_vreg_by_offset() not yet implemented") + return null; +endfunction: get_vreg_by_offset + + + +// get_addresses + +function int uvm_mem::get_addresses(uvm_reg_addr_t offset = 0, + uvm_reg_map map=null, + ref uvm_reg_addr_t addr[]); + + uvm_reg_map_info map_info; + uvm_reg_map system_map; + uvm_reg_map orig_map = map; + + map = get_local_map(map); + + if (map == null) + return 0; + + map_info = map.get_mem_map_info(this); + + if (map_info.unmapped) begin + `uvm_warning("RegModel", {"Memory '",get_name(), + "' is unmapped in map '", + ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}) + return 0; + end + + addr = map_info.addr; + + foreach (addr[i]) + addr[i] = addr[i] + map_info.mem_range.stride * offset; + + return map.get_n_bytes(); + +endfunction + + +// get_address + +function uvm_reg_addr_t uvm_mem::get_address(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + uvm_reg_addr_t addr[]; + void'(get_addresses(offset, map, addr)); + return addr[0]; +endfunction + + +// get_size + +function longint unsigned uvm_mem::get_size(); + return m_size; +endfunction: get_size + + +// get_n_bits + +function int unsigned uvm_mem::get_n_bits(); + return m_n_bits; +endfunction: get_n_bits + + +// get_max_size + +function int unsigned uvm_mem::get_max_size(); + return m_max_size; +endfunction: get_max_size + + +// get_n_bytes + +function int unsigned uvm_mem::get_n_bytes(); + return (m_n_bits - 1) / 8 + 1; +endfunction: get_n_bytes + + + + +//--------- +// COVERAGE +//--------- + + +function uvm_reg_cvr_t uvm_mem::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage + + +// add_coverage + +function void uvm_mem::add_coverage(uvm_reg_cvr_t models); + m_has_cover |= models; +endfunction: add_coverage + + +// has_coverage + +function bit uvm_mem::has_coverage(uvm_reg_cvr_t models); + return ((m_has_cover & models) == models); +endfunction: has_coverage + + +// set_coverage + +function uvm_reg_cvr_t uvm_mem::set_coverage(uvm_reg_cvr_t is_on); + if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin + m_cover_on = is_on; + return m_cover_on; + end + + m_cover_on = m_has_cover & is_on; + + return m_cover_on; +endfunction: set_coverage + + +// get_coverage + +function bit uvm_mem::get_coverage(uvm_reg_cvr_t is_on); + if (has_coverage(is_on) == 0) return 0; + return ((m_cover_on & is_on) == is_on); +endfunction: get_coverage + + + + +//----------- +// HDL ACCESS +//----------- + +// write +//------ + +task uvm_mem::write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + // create an abstract transaction for this operation +`ifdef VERILATOR + uvm_reg_item rw = uvm_reg_item::type_id_create("mem_write",,get_full_name()); +`else + uvm_reg_item rw = uvm_reg_item::type_id::create("mem_write",,get_full_name()); +`endif + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_WRITE; + rw.offset = offset; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + do_write(rw); + + status = rw.status; + +endtask: write + + +// read + +task uvm_mem::read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + uvm_reg_item rw; +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("mem_read",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("mem_read",,get_full_name()); +`endif + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_READ; + rw.value[0] = 0; + rw.offset = offset; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + do_read(rw); + + status = rw.status; + value = rw.value[0]; + +endtask: read + + +// burst_write + +task uvm_mem::burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + uvm_reg_item rw; +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("mem_burst_write",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("mem_burst_write",,get_full_name()); +`endif + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_BURST_WRITE; + rw.offset = offset; + rw.value = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + do_write(rw); + + status = rw.status; + +endtask: burst_write + + +// burst_read + +task uvm_mem::burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + ref uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + uvm_reg_item rw; +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("mem_burst_read",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("mem_burst_read",,get_full_name()); +`endif + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_BURST_READ; + rw.offset = offset; + rw.value = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + do_read(rw); + + status = rw.status; + value = rw.value; + +endtask: burst_read + + +// do_write + +task uvm_mem::do_write(uvm_reg_item rw); + + uvm_mem_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + + m_fname = rw.fname; + m_lineno = rw.lineno; + + if (!Xcheck_accessX(rw, map_info)) + return; + + m_write_in_progress = 1'b1; + + rw.status = UVM_IS_OK; + + // PRE-WRITE CBS + pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_write(rw); + + if (rw.status != UVM_IS_OK) begin + m_write_in_progress = 1'b0; + + return; + end + + rw.status = UVM_NOT_OK; + + // FRONTDOOR + if (rw.path == UVM_FRONTDOOR) begin + + uvm_reg_map system_map = rw.local_map.get_root_map(); + + if (map_info.frontdoor != null) begin + uvm_reg_frontdoor fd = map_info.frontdoor; + fd.rw_info = rw; + if (fd.sequencer == null) + fd.sequencer = system_map.get_sequencer(); + fd.start(fd.sequencer, rw.parent); + end + else begin + rw.local_map.do_write(rw); + end + + if (rw.status != UVM_NOT_OK) + for (uvm_reg_addr_t idx = rw.offset; + idx <= rw.offset + rw.value.size(); + idx++) begin + XsampleX(map_info.mem_range.stride * idx, 0, rw.map); + m_parent.XsampleX(map_info.offset + + (map_info.mem_range.stride * idx), + 0, rw.map); + end + end + + // BACKDOOR + else begin + // Mimick front door access, i.e. do not write read-only memories + if (get_access(rw.map) inside {"RW", "WO"}) begin + uvm_reg_backdoor bkdr = get_backdoor(); + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + end + else + rw.status = UVM_NOT_OK; + end + + // POST-WRITE CBS + post_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.post_write(rw); + + // REPORT + if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + string path_s,value_s,pre_s,range_s; + if (rw.path == UVM_FRONTDOOR) + path_s = (map_info.frontdoor != null) ? "user frontdoor" : + {"map ",rw.map.get_full_name()}; + else + path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; + + if (rw.value.size() > 1) begin + value_s = "='{"; + pre_s = "Burst "; + foreach (rw.value[i]) + value_s = {value_s,$sformatf("%0h,",rw.value[i])}; + value_s[value_s.len()-1]="}"; + range_s = $sformatf("[%0d:%0d]",rw.offset,rw.offset+rw.value.size()); + end + else begin + value_s = $sformatf("=%0h",rw.value[0]); + range_s = $sformatf("[%0d]",rw.offset); + end + + `uvm_info("RegModel", {pre_s,"Wrote memory via ",path_s,": ", + get_full_name(),range_s,value_s}, UVM_HIGH) + end + + m_write_in_progress = 1'b0; + +endtask: do_write + + +// do_read + +task uvm_mem::do_read(uvm_reg_item rw); + + uvm_mem_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + + m_fname = rw.fname; + m_lineno = rw.lineno; + + if (!Xcheck_accessX(rw, map_info)) + return; + + m_read_in_progress = 1'b1; + + rw.status = UVM_IS_OK; + + // PRE-READ CBS + pre_read(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_read(rw); + + if (rw.status != UVM_IS_OK) begin + m_read_in_progress = 1'b0; + + return; + end + + rw.status = UVM_NOT_OK; + + // FRONTDOOR + if (rw.path == UVM_FRONTDOOR) begin + + uvm_reg_map system_map = rw.local_map.get_root_map(); + + if (map_info.frontdoor != null) begin + uvm_reg_frontdoor fd = map_info.frontdoor; + fd.rw_info = rw; + if (fd.sequencer == null) + fd.sequencer = system_map.get_sequencer(); + fd.start(fd.sequencer, rw.parent); + end + else begin + rw.local_map.do_read(rw); + end + + if (rw.status != UVM_NOT_OK) + for (uvm_reg_addr_t idx = rw.offset; + idx <= rw.offset + rw.value.size(); + idx++) begin + XsampleX(map_info.mem_range.stride * idx, 1, rw.map); + m_parent.XsampleX(map_info.offset + + (map_info.mem_range.stride * idx), + 1, rw.map); + end + end + + // BACKDOOR + else begin + // Mimick front door access, i.e. do not read write-only memories + if (get_access(rw.map) inside {"RW", "RO"}) begin + uvm_reg_backdoor bkdr = get_backdoor(); + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + end + else + rw.status = UVM_NOT_OK; + end + + + // POST-READ CBS + post_read(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.post_read(rw); + + // REPORT + if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + string path_s,value_s,pre_s,range_s; + if (rw.path == UVM_FRONTDOOR) + path_s = (map_info.frontdoor != null) ? "user frontdoor" : + {"map ",rw.map.get_full_name()}; + else + path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; + + if (rw.value.size() > 1) begin + value_s = "='{"; + pre_s = "Burst "; + foreach (rw.value[i]) + value_s = {value_s,$sformatf("%0h,",rw.value[i])}; + value_s[value_s.len()-1]="}"; + range_s = $sformatf("[%0d:%0d]",rw.offset,(rw.offset+rw.value.size())); + end + else begin + value_s = $sformatf("=%0h",rw.value[0]); + range_s = $sformatf("[%0d]",rw.offset); + end + + `uvm_info("RegModel", {pre_s,"Read memory via ",path_s,": ", + get_full_name(),range_s,value_s}, UVM_HIGH) + end + + m_read_in_progress = 1'b0; + +endtask: do_read + + +// Xcheck_accessX + +function bit uvm_mem::Xcheck_accessX(input uvm_reg_item rw, + output uvm_reg_map_info map_info); + + if (rw.offset >= m_size) begin + `uvm_error(get_type_name(), + $sformatf("Offset 'h%0h exceeds size of memory, 'h%0h", + rw.offset, m_size)) + rw.status = UVM_NOT_OK; + return 0; + end + + if (rw.path == UVM_DEFAULT_DOOR) + rw.path = m_parent.get_default_door(); + + if (rw.path == UVM_BACKDOOR) begin + if (get_backdoor() == null && !has_hdl_path()) begin + `uvm_warning("RegModel", + {"No backdoor access available for memory '",get_full_name(), + "' . Using frontdoor instead."}) + rw.path = UVM_FRONTDOOR; + end + else if (rw.map == null) begin + if (get_default_map() != null) + rw.map = get_default_map(); + else + rw.map = uvm_reg_map::backdoor(); + end + //otherwise use the map specified in user's call to memory read/write + end + + if (rw.path != UVM_BACKDOOR) begin + + rw.local_map = get_local_map(rw.map); + + if (rw.local_map == null) begin + `uvm_error(get_type_name(), + {"No transactor available to physically access memory from map '", + rw.map.get_full_name(),"'"}) + rw.status = UVM_NOT_OK; + return 0; + end + + map_info = rw.local_map.get_mem_map_info(this); + + if (map_info.frontdoor == null) begin + + if (map_info.unmapped) begin + `uvm_error("RegModel", {"Memory '",get_full_name(), + "' unmapped in map '", rw.map.get_full_name(), + "' and does not have a user-defined frontdoor"}) + rw.status = UVM_NOT_OK; + return 0; + end + + if ((rw.value.size() > 1)) begin + if (get_n_bits() > rw.local_map.get_n_bytes()*8) begin + `uvm_error("RegModel", + $sformatf("Cannot burst a %0d-bit memory through a narrower data path (%0d bytes)", + get_n_bits(), rw.local_map.get_n_bytes()*8)) + rw.status = UVM_NOT_OK; + return 0; + end + if (rw.offset + rw.value.size() > m_size) begin + `uvm_error("RegModel", + $sformatf("Burst of size 'd%0d starting at offset 'd%0d exceeds size of memory, 'd%0d", + rw.value.size(), rw.offset, m_size)) + return 0; + end + end + end + + if (rw.map == null) + rw.map = rw.local_map; + end + + return 1; +endfunction + + +//------- +// ACCESS +//------- + +// poke + +task uvm_mem::poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + uvm_reg_backdoor bkdr = get_backdoor(); + + m_fname = fname; + m_lineno = lineno; + + if (bkdr == null && !has_hdl_path(kind)) begin + `uvm_error("RegModel", {"No backdoor access available in memory '", + get_full_name(),"'"}) + status = UVM_NOT_OK; + return; + end + + // create an abstract transaction for this operation +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("mem_poke_item",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("mem_poke_item",,get_full_name()); +`endif + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_MEM; + rw.kind = UVM_WRITE; + rw.offset = offset; + rw.value[0] = value & ((1 << m_n_bits)-1); + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + + status = rw.status; + + `uvm_info("RegModel", $sformatf("Poked memory '%s[%0d]' with value 'h%h", + get_full_name(), offset, value),UVM_HIGH) + +endtask: poke + + +// peek + +task uvm_mem::peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + + m_fname = fname; + m_lineno = lineno; + + if (bkdr == null && !has_hdl_path(kind)) begin + `uvm_error("RegModel", {"No backdoor access available in memory '", + get_full_name(),"'"}) + status = UVM_NOT_OK; + return; + end + + // create an abstract transaction for this operation +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("mem_peek_item",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("mem_peek_item",,get_full_name()); +`endif + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_MEM; + rw.kind = UVM_READ; + rw.offset = offset; + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + + status = rw.status; + value = rw.value[0]; + + `uvm_info("RegModel", $sformatf("Peeked memory '%s[%0d]' has value 'h%h", + get_full_name(), offset, value),UVM_HIGH) +endtask: peek + + +//----------------- +// Group- Frontdoor +//----------------- + +// set_frontdoor + +function void uvm_mem::set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_map_info map_info; + m_fname = fname; + m_lineno = lineno; + + map = get_local_map(map); + + if (map == null) begin + `uvm_error("RegModel", {"Memory '",get_full_name(), + "' not found in map '", map.get_full_name(),"'"}) + return; + end + + map_info = map.get_mem_map_info(this); + map_info.frontdoor = ftdr; + +endfunction: set_frontdoor + + +// get_frontdoor + +function uvm_reg_frontdoor uvm_mem::get_frontdoor(uvm_reg_map map = null); + uvm_reg_map_info map_info; + + map = get_local_map(map); + + if (map == null) begin + `uvm_error("RegModel", {"Memory '",get_full_name(), + "' not found in map '", map.get_full_name(),"'"}) + return null; + end + + map_info = map.get_mem_map_info(this); + return map_info.frontdoor; + +endfunction: get_frontdoor + + +//---------------- +// Group- Backdoor +//---------------- + +// set_backdoor + +function void uvm_mem::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + m_backdoor = bkdr; +endfunction: set_backdoor + + +// get_backdoor + +function uvm_reg_backdoor uvm_mem::get_backdoor(bit inherited = 1); + + if (m_backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + uvm_reg_backdoor bkdr; + while (blk != null) begin + bkdr = blk.get_backdoor(); + if (bkdr != null) begin + m_backdoor = bkdr; + break; + end + blk = blk.get_parent(); + end + end + + return m_backdoor; +endfunction: get_backdoor + + +// backdoor_read_func + +function uvm_status_e uvm_mem::backdoor_read_func(uvm_reg_item rw); + + uvm_hdl_path_concat paths[$]; + uvm_hdl_data_t val; + bit ok=1; + + get_full_hdl_path(paths,rw.bd_kind); + + foreach (rw.value[mem_idx]) begin + string idx; + idx.itoa(rw.offset + mem_idx); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + val = 0; + foreach (hdl_concat.slices[j]) begin + string hdl_path = {hdl_concat.slices[j].path, "[", idx, "]"}; + + `uvm_info("RegModel", {"backdoor_read from ",hdl_path},UVM_DEBUG) + + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_read(hdl_path, val); + continue; + end + begin + uvm_reg_data_t slice; + int k = hdl_concat.slices[j].offset; + ok &= uvm_hdl_read(hdl_path, slice); + repeat (hdl_concat.slices[j].size) begin + val[k++] = slice[0]; + slice >>= 1; + end + end + end + + val &= (1 << m_n_bits)-1; + + if (i == 0) + rw.value[mem_idx] = val; + + if (val != rw.value[mem_idx]) begin + `uvm_error("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", + get_full_name(), rw.value[mem_idx], uvm_hdl_concat2string(paths[0]), + val, uvm_hdl_concat2string(paths[i]))) + return UVM_NOT_OK; + end + end + end + + rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; + + return rw.status; +endfunction + + +// backdoor_read + +task uvm_mem::backdoor_read(uvm_reg_item rw); + rw.status = backdoor_read_func(rw); +endtask + + +// backdoor_write + +task uvm_mem::backdoor_write(uvm_reg_item rw); + + uvm_hdl_path_concat paths[$]; + bit ok=1; + + + get_full_hdl_path(paths,rw.bd_kind); + + foreach (rw.value[mem_idx]) begin + string idx; + idx.itoa(rw.offset + mem_idx); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + foreach (hdl_concat.slices[j]) begin + `uvm_info("RegModel", $sformatf("backdoor_write to %s ",hdl_concat.slices[j].path),UVM_DEBUG) + + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_deposit({hdl_concat.slices[j].path,"[", idx, "]"},rw.value[mem_idx]); + continue; + end + begin + uvm_reg_data_t slice; + slice = rw.value[mem_idx] >> hdl_concat.slices[j].offset; + slice &= (1 << hdl_concat.slices[j].size)-1; + ok &= uvm_hdl_deposit({hdl_concat.slices[j].path, "[", idx, "]"}, slice); + end + end + end + end + rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); +endtask + + + + +// clear_hdl_path + +function void uvm_mem::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + m_hdl_paths_pool = new("hdl_paths"); + return; + end + + if (kind == "") + kind = m_parent.get_default_hdl_path(); + + if (!m_hdl_paths_pool.exists(kind)) begin + `uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"}) + return; + end + + m_hdl_paths_pool.delete(kind); +endfunction + + +// add_hdl_path + +function void uvm_mem::add_hdl_path(uvm_hdl_path_slice slices[], string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat = new(); + + concat.set(slices); + paths.push_back(concat); +endfunction + + +// add_hdl_path_slice + +function void uvm_mem::add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths=m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat; + + if (first || paths.size() == 0) begin + concat = new(); + paths.push_back(concat); + end + else + concat = paths.get(paths.size()-1); + + concat.add_path(name, offset, size); +endfunction + + +// has_hdl_path + +function bit uvm_mem::has_hdl_path(string kind = ""); + if (kind == "") + kind = m_parent.get_default_hdl_path(); + + return m_hdl_paths_pool.exists(kind); +endfunction + + +// get_hdl_path + +function void uvm_mem::get_hdl_path(ref uvm_hdl_path_concat paths[$], + input string kind = ""); + + uvm_queue #(uvm_hdl_path_concat) hdl_paths; + + if (kind == "") + kind = m_parent.get_default_hdl_path(); + + if (!has_hdl_path(kind)) begin + `uvm_error("RegModel", + {"Memory does not have hdl path defined for abstraction '",kind,"'"}) + return; + end + + hdl_paths = m_hdl_paths_pool.get(kind); + + for (int i=0; i and + // methods. + // + extern function new(string name, + uvm_mem_mam_cfg cfg, + uvm_mem mem=null); + + + // Function -- NODOCS -- reconfigure + // + // Reconfigure the manager + // + // Modify the maximum and minimum addresses of the address space managed by + // the allocation manager, allocation mode, or locality. + // The number of bytes per memory location cannot be modified + // once an allocation manager has been constructed. + // All currently allocated regions must fall within the new address space. + // + // Returns the previous configuration. + // + // if no new configuration is specified, simply returns the current + // configuration. + // + extern function uvm_mem_mam_cfg reconfigure(uvm_mem_mam_cfg cfg = null); + + + //------------------------- + // Group -- NODOCS -- Memory Management + //------------------------- + + // Function -- NODOCS -- reserve_region + // + // Reserve a specific memory region + // + // Reserve a memory region of the specified number of bytes + // starting at the specified offset. + // A descriptor of the reserved region is returned. + // If the specified region cannot be reserved, ~null~ is returned. + // + // It may not be possible to reserve a region because + // it overlaps with an already-allocated region or + // it lies outside the address range managed + // by the memory manager. + // + // Regions can be reserved to create "holes" in the managed address space. + // + extern function uvm_mem_region reserve_region(bit [63:0] start_offset, + int unsigned n_bytes, + string fname = "", + int lineno = 0); + + + // Function -- NODOCS -- request_region + // + // Request and reserve a memory region + // + // Request and reserve a memory region of the specified number + // of bytes starting at a random location. + // If an policy is specified, it is randomized to determine + // the start offset of the region. + // If no policy is specified, the policy found in + // the class property is randomized. + // + // A descriptor of the allocated region is returned. + // If no region can be allocated, ~null~ is returned. + // + // It may not be possible to allocate a region because + // there is no area in the memory with enough consecutive locations + // to meet the size requirements or + // because there is another contradiction when randomizing + // the policy. + // + // If the memory allocation is configured to ~THRIFTY~ or ~NEARBY~, + // a suitable region is first sought procedurally. + // + extern function uvm_mem_region request_region(int unsigned n_bytes, + uvm_mem_mam_policy alloc = null, + string fname = "", + int lineno = 0); + + + // Function -- NODOCS -- release_region + // + // Release the specified region + // + // Release a previously allocated memory region. + // An error is issued if the + // specified region has not been previously allocated or + // is no longer allocated. + // + extern function void release_region(uvm_mem_region region); + + + // Function -- NODOCS -- release_all_regions + // + // Forcibly release all allocated memory regions. + // + extern function void release_all_regions(); + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // Function -- NODOCS -- convert2string + // + // Image of the state of the manager + // + // Create a human-readable description of the state of + // the memory manager and the currently allocated regions. + // + extern function string convert2string(); + + + // Function -- NODOCS -- for_each + // + // Iterate over all currently allocated regions + // + // If reset is ~TRUE~, reset the iterator + // and return the first allocated region. + // Returns ~null~ when there are no additional allocated + // regions to iterate on. + // + extern function uvm_mem_region for_each(bit reset = 0); + + + // Function -- NODOCS -- get_memory + // + // Get the managed memory implementation + // + // Return the reference to the memory abstraction class + // for the memory implementing + // the locations managed by this instance of the allocation manager. + // Returns ~null~ if no + // memory abstraction class was specified at construction time. + // + extern function uvm_mem get_memory(); + +endclass: uvm_mem_mam + + + +//------------------------------------------------------------------------------ +// CLASS -- NODOCS -- uvm_mem_region +//------------------------------------------------------------------------------ +// Allocated memory region descriptor +// +// Each instance of this class describes an allocated memory region. +// Instances of this class are created only by +// the memory manager, and returned by the +// and +// methods. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.12.7.1 +class uvm_mem_region; + + /*local*/ bit [63:0] Xstart_offsetX; // Can't be local since function + /*local*/ bit [63:0] Xend_offsetX; // calls not supported in constraints + + local int unsigned len; + local int unsigned n_bytes; + local uvm_mem_mam parent; + local string fname; + local int lineno; + + /*local*/ uvm_vreg XvregX; + + extern /*local*/ function new(bit [63:0] start_offset, + bit [63:0] end_offset, + int unsigned len, + int unsigned n_bytes, + uvm_mem_mam parent); + + // Function -- NODOCS -- get_start_offset + // + // Get the start offset of the region + // + // Return the address offset, within the memory, + // where this memory region starts. + // + extern function bit [63:0] get_start_offset(); + + + // Function -- NODOCS -- get_end_offset + // + // Get the end offset of the region + // + // Return the address offset, within the memory, + // where this memory region ends. + // + extern function bit [63:0] get_end_offset(); + + + // Function -- NODOCS -- get_len + // + // Size of the memory region + // + // Return the number of consecutive memory locations + // (not necessarily bytes) in the allocated region. + // + extern function int unsigned get_len(); + + + // Function -- NODOCS -- get_n_bytes + // + // Number of bytes in the region + // + // Return the number of consecutive bytes in the allocated region. + // If the managed memory contains more than one byte per address, + // the number of bytes in an allocated region may + // be greater than the number of requested or reserved bytes. + // + extern function int unsigned get_n_bytes(); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.5 + extern function void release_region(); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.6 + extern function uvm_mem get_memory(); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.7 + extern function uvm_vreg get_virtual_registers(); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.8 + extern task write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.9 + extern task read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.10 + extern task burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.11 + extern task burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.12 + extern task poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.12.7.2.13 + extern task peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + extern function string convert2string(); + +endclass + + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_mem_mam_policy +//------------------------------------------------------------------------------ +// +// An instance of this class is randomized to determine +// the starting offset of a randomly allocated memory region. +// This class can be extended to provide additional constraints +// on the starting offset, such as word alignment or +// location of the region within a memory page. +// If a procedural region allocation policy is required, +// it can be implemented in the pre/post_randomize() method. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.12.8.1 +class uvm_mem_mam_policy; + // variable -- NODOCS -- len + // Number of addresses required + int unsigned len; + + // variable -- NODOCS -- start_offset + // The starting offset of the region + rand bit [63:0] start_offset; + + // variable -- NODOCS -- min_offset + // Minimum address offset in the managed address space + bit [63:0] min_offset; + + // variable -- NODOCS -- max_offset + // Maximum address offset in the managed address space + bit [63:0] max_offset; + + // variable -- NODOCS -- in_use + // Regions already allocated in the managed address space + uvm_mem_region in_use[$]; + + constraint uvm_mem_mam_policy_valid { + start_offset >= min_offset; + start_offset <= max_offset - len + 1; + } + + constraint uvm_mem_mam_policy_no_overlap { + foreach (in_use[i]) { + !(start_offset <= in_use[i].Xend_offsetX && + start_offset + len - 1 >= in_use[i].Xstart_offsetX); + } + } + +endclass + + + + +// @uvm-ieee 1800.2-2017 auto 18.12.9.1 +class uvm_mem_mam_cfg; + // variable -- NODOCS -- n_bytes + // Number of bytes in each memory location + rand int unsigned n_bytes; + +// Mantis 6601 calls for these two offset fields to be type longint unsigned + // variable -- NODOCS -- start_offset + // Lowest address of managed space + rand bit [63:0] start_offset; + + // variable -- NODOCS -- end_offset + // Last address of managed space + rand bit [63:0] end_offset; + + // variable -- NODOCS -- mode + // Region allocation mode + rand uvm_mem_mam::alloc_mode_e mode; + + // variable -- NODOCS -- locality + // Region location mode + rand uvm_mem_mam::locality_e locality; + + constraint uvm_mem_mam_cfg_valid { + end_offset > start_offset; + n_bytes < 64; + } +endclass + + + +//------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------ + +function uvm_mem_region::new(bit [63:0] start_offset, + bit [63:0] end_offset, + int unsigned len, + int unsigned n_bytes, + uvm_mem_mam parent); + this.Xstart_offsetX = start_offset; + this.Xend_offsetX = end_offset; + this.len = len; + this.n_bytes = n_bytes; + this.parent = parent; + this.XvregX = null; +endfunction: new + + +function bit [63:0] uvm_mem_region::get_start_offset(); + return this.Xstart_offsetX; +endfunction: get_start_offset + + +function bit [63:0] uvm_mem_region::get_end_offset(); + return this.Xend_offsetX; +endfunction: get_end_offset + + +function int unsigned uvm_mem_region::get_len(); + return this.len; +endfunction: get_len + + +function int unsigned uvm_mem_region::get_n_bytes(); + return this.n_bytes; +endfunction: get_n_bytes + + +function string uvm_mem_region::convert2string(); + $sformat(convert2string, "['h%h:'h%h]", + this.Xstart_offsetX, this.Xend_offsetX); +endfunction: convert2string + + +function void uvm_mem_region::release_region(); + this.parent.release_region(this); +endfunction + + +function uvm_mem uvm_mem_region::get_memory(); + return this.parent.get_memory(); +endfunction: get_memory + + +function uvm_vreg uvm_mem_region::get_virtual_registers(); + return this.XvregX; +endfunction: get_virtual_registers + + +function uvm_mem_mam::new(string name, + uvm_mem_mam_cfg cfg, + uvm_mem mem = null); + this.cfg = cfg; + this.memory = mem; + this.default_alloc = new; +endfunction: new + + +function uvm_mem_mam_cfg uvm_mem_mam::reconfigure(uvm_mem_mam_cfg cfg = null); + uvm_root top; + uvm_coreservice_t cs; + if (cfg == null) + return this.cfg; + + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + // Cannot reconfigure n_bytes + if (cfg.n_bytes !== this.cfg.n_bytes) begin + top.uvm_report_error("uvm_mem_mam", + $sformatf("Cannot reconfigure Memory Allocation Manager with a different number of bytes (%0d !== %0d)", + cfg.n_bytes, this.cfg.n_bytes), UVM_LOW); + return this.cfg; + end + + // All currently allocated regions must fall within the new space + foreach (this.in_use[i]) begin + if (this.in_use[i].get_start_offset() < cfg.start_offset || + this.in_use[i].get_end_offset() > cfg.end_offset) begin + top.uvm_report_error("uvm_mem_mam", + $sformatf("Cannot reconfigure Memory Allocation Manager with a currently allocated region outside of the managed address range ([%0d:%0d] outside of [%0d:%0d])", + this.in_use[i].get_start_offset(), + this.in_use[i].get_end_offset(), + cfg.start_offset, cfg.end_offset), UVM_LOW); + return this.cfg; + end + end + + reconfigure = this.cfg; + this.cfg = cfg; +endfunction: reconfigure + + +function uvm_mem_region uvm_mem_mam::reserve_region(bit [63:0] start_offset, + int unsigned n_bytes, + string fname = "", + int lineno = 0); + bit [63:0] end_offset; + this.fname = fname; + this.lineno = lineno; + if (n_bytes == 0) begin + `uvm_error("RegModel", "Cannot reserve 0 bytes") + return null; + end + + if (start_offset < this.cfg.start_offset) begin + `uvm_error("RegModel", $sformatf("Cannot reserve before start of memory space: 'h%h < 'h%h", + start_offset, this.cfg.start_offset)) + return null; + end + + end_offset = start_offset + ((n_bytes-1) / this.cfg.n_bytes); + n_bytes = (end_offset - start_offset + 1) * this.cfg.n_bytes; + + if (end_offset > this.cfg.end_offset) begin + `uvm_error("RegModel", $sformatf("Cannot reserve past end of memory space: 'h%h > 'h%h", + end_offset, this.cfg.end_offset)) + return null; + end + + `uvm_info("RegModel",$sformatf("Attempting to reserve ['h%h:'h%h]...", + start_offset, end_offset),UVM_MEDIUM) + + + + + foreach (this.in_use[i]) begin + if (start_offset <= this.in_use[i].get_end_offset() && + end_offset >= this.in_use[i].get_start_offset()) begin + // Overlap! + `uvm_error("RegModel", $sformatf("Cannot reserve ['h%h:'h%h] because it overlaps with %s", + start_offset, end_offset, + this.in_use[i].convert2string())) + return null; + end + + // Regions are stored in increasing start offset + if (start_offset > this.in_use[i].get_start_offset()) begin + reserve_region = new(start_offset, end_offset, + end_offset - start_offset + 1, n_bytes, this); + this.in_use.insert(i, reserve_region); + return reserve_region; + end + end + + reserve_region = new(start_offset, end_offset, + end_offset - start_offset + 1, n_bytes, this); + this.in_use.push_back(reserve_region); +endfunction: reserve_region + + +function uvm_mem_region uvm_mem_mam::request_region(int unsigned n_bytes, + uvm_mem_mam_policy alloc = null, + string fname = "", + int lineno = 0); + this.fname = fname; + this.lineno = lineno; + if (alloc == null) alloc = this.default_alloc; + + alloc.len = (n_bytes-1) / this.cfg.n_bytes + 1; + alloc.min_offset = this.cfg.start_offset; + alloc.max_offset = this.cfg.end_offset; + alloc.in_use = this.in_use; + + if (!alloc.randomize()) begin + `uvm_error("RegModel", "Unable to randomize policy") + return null; + end + + return reserve_region(alloc.start_offset, n_bytes); +endfunction: request_region + + +function void uvm_mem_mam::release_region(uvm_mem_region region); + + if (region == null) return; + + foreach (this.in_use[i]) begin + if (this.in_use[i] == region) begin + this.in_use.delete(i); + return; + end + end + `uvm_error("RegModel", {"Attempting to release unallocated region\n", + region.convert2string()}) +endfunction: release_region + + +function void uvm_mem_mam::release_all_regions(); + in_use.delete(); +endfunction: release_all_regions + + +function string uvm_mem_mam::convert2string(); + convert2string = "Allocated memory regions:\n"; + foreach (this.in_use[i]) begin + $sformat(convert2string, "%s %s\n", convert2string, + this.in_use[i].convert2string()); + end +endfunction: convert2string + + +function uvm_mem_region uvm_mem_mam::for_each(bit reset = 0); + if (reset) this.for_each_idx = -1; + + this.for_each_idx++; + + if (this.for_each_idx >= this.in_use.size()) begin + return null; + end + + return this.in_use[this.for_each_idx]; +endfunction: for_each + + +function uvm_mem uvm_mem_mam::get_memory(); + return this.memory; +endfunction: get_memory + + +task uvm_mem_region::write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + + if (mem == null) begin + `uvm_error("RegModel", "Cannot use uvm_mem_region::write() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance") + status = UVM_NOT_OK; + return; + end + + if (offset > this.len) begin + `uvm_error("RegModel", + $sformatf("Attempting to write to an offset outside of the allocated region (%0d > %0d)", + offset, this.len)) + status = UVM_NOT_OK; + return; + end + + mem.write(status, offset + this.get_start_offset(), value, + path, map, parent, prior, extension); +endtask: write + + +task uvm_mem_region::read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + + if (mem == null) begin + `uvm_error("RegModel", "Cannot use uvm_mem_region::read() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance") + status = UVM_NOT_OK; + return; + end + + if (offset > this.len) begin + `uvm_error("RegModel", + $sformatf("Attempting to read from an offset outside of the allocated region (%0d > %0d)", + offset, this.len)) + status = UVM_NOT_OK; + return; + end + + mem.read(status, offset + this.get_start_offset(), value, + path, map, parent, prior, extension); +endtask: read + + +task uvm_mem_region::burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + + if (mem == null) begin + `uvm_error("RegModel", "Cannot use uvm_mem_region::burst_write() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance") + status = UVM_NOT_OK; + return; + end + + if (offset + value.size() > this.len) begin + `uvm_error("RegModel", + $sformatf("Attempting to burst-write to an offset outside of the allocated region (burst to [%0d:%0d] > mem_size %0d)", + offset,offset+value.size(),this.len)) + status = UVM_NOT_OK; + return; + end + + mem.burst_write(status, offset + get_start_offset(), value, + path, map, parent, prior, extension); + +endtask: burst_write + + +task uvm_mem_region::burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + + if (mem == null) begin + `uvm_error("RegModel", "Cannot use uvm_mem_region::burst_read() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance") + status = UVM_NOT_OK; + return; + end + + if (offset + value.size() > this.len) begin + `uvm_error("RegModel", + $sformatf("Attempting to burst-read to an offset outside of the allocated region (burst to [%0d:%0d] > mem_size %0d)", + offset,offset+value.size(),this.len)) + status = UVM_NOT_OK; + return; + end + + mem.burst_read(status, offset + get_start_offset(), value, + path, map, parent, prior, extension); + +endtask: burst_read + + +task uvm_mem_region::poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + + if (mem == null) begin + `uvm_error("RegModel", "Cannot use uvm_mem_region::poke() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance") + status = UVM_NOT_OK; + return; + end + + if (offset > this.len) begin + `uvm_error("RegModel", + $sformatf("Attempting to poke to an offset outside of the allocated region (%0d > %0d)", + offset, this.len)) + status = UVM_NOT_OK; + return; + end + + mem.poke(status, offset + this.get_start_offset(), value, "", parent, extension); +endtask: poke + + +task uvm_mem_region::peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + + if (mem == null) begin + `uvm_error("RegModel", "Cannot use uvm_mem_region::peek() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance") + status = UVM_NOT_OK; + return; + end + + if (offset > this.len) begin + `uvm_error("RegModel", + $sformatf("Attempting to peek from an offset outside of the allocated region (%0d > %0d)", + offset, this.len)) + status = UVM_NOT_OK; + return; + end + + mem.peek(status, offset + this.get_start_offset(), value, "", parent, extension); +endtask: peek + + +`endif // UVM_MEM_MAM__SV diff --git a/test_regress/t/t_uvm/reg/uvm_reg.svh b/test_regress/t/t_uvm/reg/uvm_reg.svh new file mode 100644 index 0000000000..ebdcba129b --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg.svh @@ -0,0 +1,2575 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2012 Mentor Graphics Corporation +// Copyright 2011-2014 Semifore +// Copyright 2018 Intel Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// 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. +// ------------------------------------------------------------- +// + +typedef class uvm_reg_cbs; +typedef class uvm_reg_frontdoor; + + +// @uvm-ieee 1800.2-2017 auto 18.4.1 +class uvm_reg extends uvm_object; + + local bit m_locked; + local uvm_reg_block m_parent; + local uvm_reg_file m_regfile_parent; + local int unsigned m_n_bits; + local int unsigned m_n_used_bits; + protected bit m_maps[uvm_reg_map]; + protected uvm_reg_field m_fields[$]; // Fields in LSB to MSB order + local int m_has_cover; + local int m_cover_on; + local semaphore m_atomic; + local process m_process; + local string m_fname; + local int m_lineno; + local bit m_read_in_progress; + local bit m_write_in_progress; + protected bit m_update_in_progress; + /*local*/ bit m_is_busy; + /*local*/ bit m_is_locked_by_field; + local uvm_reg_backdoor m_backdoor; + + local static int unsigned m_max_size; + + local uvm_object_string_pool + #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; + + //---------------------- + // Group -- NODOCS -- Initialization + //---------------------- + + + // @uvm-ieee 1800.2-2017 auto 18.4.2.1 + extern function new (string name="", + int unsigned n_bits, + int has_coverage); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.2.2 + extern function void configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent = null, + string hdl_path = ""); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.2.3 + extern virtual function void set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + + /*local*/ extern virtual function void set_parent (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent); + /*local*/ extern virtual function void add_field (uvm_reg_field field); + /*local*/ extern virtual function void add_map (uvm_reg_map map); + + /*local*/ extern function void Xlock_modelX; + + // remove the knowledge that the register resides in the map from the register instance + // @uvm-ieee 1800.2-2017 auto 18.4.2.5 + virtual function void unregister(uvm_reg_map map); + m_maps.delete(map); + endfunction + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // Function -- NODOCS -- get_name + // + // Get the simple name + // + // Return the simple object name of this register. + // + + // Function -- NODOCS -- get_full_name + // + // Get the hierarchical name + // + // Return the hierarchal name of this register. + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.1 + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.2 + extern virtual function uvm_reg_file get_regfile (); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.3 + extern virtual function int get_n_maps (); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.4 + extern function bit is_in_map (uvm_reg_map map); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.5 + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + + + /*local*/ extern virtual function uvm_reg_map get_local_map (uvm_reg_map map); + /*local*/ extern virtual function uvm_reg_map get_default_map (); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.6 + extern virtual function string get_rights (uvm_reg_map map = null); + + + // Function -- NODOCS -- get_n_bits + // + // Returns the width, in bits, of this register. + // + extern virtual function int unsigned get_n_bits (); + + + // Function -- NODOCS -- get_n_bytes + // + // Returns the width, in bytes, of this register. Rounds up to + // next whole byte if register is not a multiple of 8. + // + extern virtual function int unsigned get_n_bytes(); + + + // Function -- NODOCS -- get_max_size + // + // Returns the maximum width, in bits, of all registers. + // + extern static function int unsigned get_max_size(); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.10 + extern virtual function void get_fields (ref uvm_reg_field fields[$]); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.11 + extern virtual function uvm_reg_field get_field_by_name(string name); + + + /*local*/ extern function string Xget_fields_accessX(uvm_reg_map map); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.12 + extern virtual function uvm_reg_addr_t get_offset (uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.13 + extern virtual function uvm_reg_addr_t get_address (uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.3.14 + extern virtual function int get_addresses (uvm_reg_map map = null, + ref uvm_reg_addr_t addr[]); + + + + //-------------- + // Group -- NODOCS -- Access + //-------------- + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.2 + extern virtual function void set (uvm_reg_data_t value, + string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.1 + extern virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.3 + extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.4 + extern virtual function bit needs_update(); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.5 + extern virtual function void reset(string kind = "HARD"); + + + // Function -- NODOCS -- get_reset + // + // Get the specified reset value for this register + // + // Return the reset value for this register + // for the specified reset ~kind~. + // + extern virtual function uvm_reg_data_t + // @uvm-ieee 1800.2-2017 auto 18.4.4.6 + get_reset(string kind = "HARD"); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.7 + extern virtual function bit has_reset(string kind = "HARD", + bit delete = 0); + + + // Function -- NODOCS -- set_reset + // + // Specify or modify the reset value for this register + // + // Specify or modify the reset value for all the fields in the register + // corresponding to the cause specified by ~kind~. + // + extern virtual function void + // @uvm-ieee 1800.2-2017 auto 18.4.4.8 + set_reset(uvm_reg_data_t value, + string kind = "HARD"); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.9 + // @uvm-ieee 1800.2-2017 auto 18.8.5.3 + extern virtual task write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.10 + // @uvm-ieee 1800.2-2017 auto 18.8.5.4 + extern virtual task read(output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.11 + // @uvm-ieee 1800.2-2017 auto 18.8.5.5 + // @uvm-ieee 1800.2-2017 auto 18.8.5.6 + extern virtual task poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.12 + extern virtual task peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.13 + extern virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.14 + // @uvm-ieee 1800.2-2017 auto 18.8.5.8 + extern virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.15 + // @uvm-ieee 1800.2-2017 auto 18.8.5.9 + extern virtual function bit predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.4.16 + extern function bit is_busy(); + + + + /*local*/ extern function void Xset_busyX(bit busy); + + /*local*/ extern task XreadX (output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path, + input uvm_reg_map map, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + /*local*/ extern task XatomicX(bit on); + + /*local*/ extern virtual function bit Xcheck_accessX + (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + + /*local*/ extern function bit Xis_locked_by_fieldX(); + + + extern virtual function bit do_check(uvm_reg_data_t expected, + uvm_reg_data_t actual, + uvm_reg_map map); + + extern virtual task do_write(uvm_reg_item rw); + + extern virtual task do_read(uvm_reg_item rw); + + extern virtual function void do_predict + (uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + //----------------- + // Group -- NODOCS -- Frontdoor + //----------------- + + + // @uvm-ieee 1800.2-2017 auto 18.4.5.2 + extern function void set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.5.1 + extern function uvm_reg_frontdoor get_frontdoor(uvm_reg_map map = null); + + + //---------------- + // Group -- NODOCS -- Backdoor + //---------------- + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.2 + extern function void set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.1 + extern function uvm_reg_backdoor get_backdoor(bit inherited = 1); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.3 + extern function void clear_hdl_path (string kind = "RTL"); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.4 + extern function void add_hdl_path (uvm_hdl_path_slice slices[], + string kind = "RTL"); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.5 + extern function void add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.6 + extern function bit has_hdl_path (string kind = ""); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.7 + extern function void get_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = ""); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.8 + extern function void get_hdl_path_kinds (ref string kinds[$]); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.9 + extern function void get_full_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = "", + input string separator = "."); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.10 + extern virtual task backdoor_read(uvm_reg_item rw); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.11 + extern virtual task backdoor_write(uvm_reg_item rw); + + + + extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.6.12 + virtual task backdoor_watch(); endtask + + + //---------------- + // Group -- NODOCS -- Coverage + //---------------- + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.1 + extern static function void include_coverage(string scope, + uvm_reg_cvr_t models, + uvm_object accessor = null); + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.2 + extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.3 + extern virtual protected function void add_coverage(uvm_reg_cvr_t models); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.4 + extern virtual function bit has_coverage(uvm_reg_cvr_t models); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.6 + extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.5 + extern virtual function bit get_coverage(uvm_reg_cvr_t is_on); + + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.7 + protected virtual function void sample(uvm_reg_data_t data, + uvm_reg_data_t byte_en, + bit is_read, + uvm_reg_map map); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 18.4.7.8 + virtual function void sample_values(); + endfunction + + /*local*/ function void XsampleX(uvm_reg_data_t data, + uvm_reg_data_t byte_en, + bit is_read, + uvm_reg_map map); + sample(data, byte_en, is_read, map); + endfunction + + + //----------------- + // Group -- NODOCS -- Callbacks + //----------------- + `uvm_register_cb(uvm_reg, uvm_reg_cbs) + + + + // @uvm-ieee 1800.2-2017 auto 18.4.8.1 + virtual task pre_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.4.8.2 + virtual task post_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.4.8.3 + virtual task pre_read(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.4.8.4 + virtual task post_read(uvm_reg_item rw); endtask + + + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone (); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + +endclass: uvm_reg + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// new + +function uvm_reg::new(string name="", int unsigned n_bits, int has_coverage); + super.new(name); + if (n_bits == 0) begin + `uvm_error("RegModel", $sformatf("Register \"%s\" cannot have 0 bits", get_name())) + n_bits = 1; + end + m_n_bits = n_bits; + m_has_cover = has_coverage; + m_atomic = new(1); + m_n_used_bits = 0; + m_locked = 0; + m_is_busy = 0; + m_is_locked_by_field = 1'b0; + m_hdl_paths_pool = new("hdl_paths"); + + if (n_bits > m_max_size) + m_max_size = n_bits; + +endfunction: new + + +// configure + +function void uvm_reg::configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent=null, + string hdl_path = ""); + if (blk_parent == null) begin + `uvm_error("UVM/REG/CFG/NOBLK", {"uvm_reg::configure() called without a parent block for instance \"", get_name(), "\" of register type \"", get_type_name(), "\"."}) + return; + end + + m_parent = blk_parent; + m_parent.add_reg(this); + m_regfile_parent = regfile_parent; + if (hdl_path != "") + add_hdl_path_slice(hdl_path, -1, -1); +endfunction: configure + + +// add_field + +function void uvm_reg::add_field(uvm_reg_field field); + int offset; + int idx; + + if (m_locked) begin + `uvm_error("RegModel", "Cannot add field to locked register model") + return; + end + + if (field == null) `uvm_fatal("RegModel", "Attempting to register NULL field") + + // Store fields in LSB to MSB order + offset = field.get_lsb_pos(); + + idx = -1; + foreach (m_fields[i]) begin + if (offset < m_fields[i].get_lsb_pos()) begin + int j = i; + m_fields.insert(j, field); + idx = i; + break; + end + end + if (idx < 0) begin + m_fields.push_back(field); + idx = m_fields.size()-1; + end + + m_n_used_bits += field.get_n_bits(); + + // Check if there are too many fields in the register + if (m_n_used_bits > m_n_bits) begin + `uvm_error("RegModel", + $sformatf("Fields use more bits (%0d) than available in register \"%s\" (%0d)", + m_n_used_bits, get_name(), m_n_bits)) + end + + // Check if there are overlapping fields + if (idx > 0) begin + if (m_fields[idx-1].get_lsb_pos() + + m_fields[idx-1].get_n_bits() > offset) begin + `uvm_error("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"", + m_fields[idx-1].get_name(), + field.get_name(), get_name())) + end + end + if (idx < m_fields.size()-1) begin + if (offset + field.get_n_bits() > + m_fields[idx+1].get_lsb_pos()) begin + `uvm_error("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"", + field.get_name(), + m_fields[idx+1].get_name(), + get_name())) + end + end +endfunction: add_field + + +// Xlock_modelX + +function void uvm_reg::Xlock_modelX(); + if (m_locked) + return; + m_locked = 1; +endfunction + + +//---------------------- +// Group- User Frontdoor +//---------------------- + +// set_frontdoor + +function void uvm_reg::set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_map_info map_info; + ftdr.fname = m_fname; + ftdr.lineno = m_lineno; + map = get_local_map(map); + if (map == null) + return; + map_info = map.get_reg_map_info(this); + if (map_info == null) + map.add_reg(this, -1, "RW", 1, ftdr); + else begin + map_info.frontdoor = ftdr; + end +endfunction: set_frontdoor + + +// get_frontdoor + +function uvm_reg_frontdoor uvm_reg::get_frontdoor(uvm_reg_map map = null); + uvm_reg_map_info map_info; + map = get_local_map(map); + if (map == null) + return null; + map_info = map.get_reg_map_info(this); + return map_info.frontdoor; +endfunction: get_frontdoor + + +// set_backdoor + +function void uvm_reg::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + bkdr.fname = fname; + bkdr.lineno = lineno; + if (m_backdoor != null && + m_backdoor.has_update_threads()) begin + `uvm_warning("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.") + end + m_backdoor = bkdr; +endfunction: set_backdoor + + +// get_backdoor + +function uvm_reg_backdoor uvm_reg::get_backdoor(bit inherited = 1); + + if (m_backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + uvm_reg_backdoor bkdr; + while (blk != null) begin + bkdr = blk.get_backdoor(); + if (bkdr != null) begin + m_backdoor = bkdr; + break; + end + blk = blk.get_parent(); + end + end + return m_backdoor; +endfunction: get_backdoor + + + +// clear_hdl_path + +function void uvm_reg::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + m_hdl_paths_pool = new("hdl_paths"); + return; + end + + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + + if (!m_hdl_paths_pool.exists(kind)) begin + `uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"}) + return; + end + + m_hdl_paths_pool.delete(kind); +endfunction + + +// add_hdl_path + +function void uvm_reg::add_hdl_path(uvm_hdl_path_slice slices[], + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat = new(); + + concat.set(slices); + paths.push_back(concat); +endfunction + + +// add_hdl_path_slice + +function void uvm_reg::add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat; + + if (first || paths.size() == 0) begin + concat = new(); + paths.push_back(concat); + end + else + concat = paths.get(paths.size()-1); + + concat.add_path(name, offset, size); +endfunction + + +// has_hdl_path + +function bit uvm_reg::has_hdl_path(string kind = ""); + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + + return m_hdl_paths_pool.exists(kind); +endfunction + + +// get_hdl_path_kinds + +function void uvm_reg::get_hdl_path_kinds (ref string kinds[$]); + string kind; + kinds.delete(); + if (!m_hdl_paths_pool.first(kind)) + return; + do + kinds.push_back(kind); + while (m_hdl_paths_pool.next(kind)); +endfunction + + +// get_hdl_path + +function void uvm_reg::get_hdl_path(ref uvm_hdl_path_concat paths[$], + input string kind = ""); + + uvm_queue #(uvm_hdl_path_concat) hdl_paths; + + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + + if (!has_hdl_path(kind)) begin + `uvm_error("RegModel", + {"Register does not have hdl path defined for abstraction '",kind,"'"}) + return; + end + + hdl_paths = m_hdl_paths_pool.get(kind); + + for (int i=0; i 1 && map == null) begin + `uvm_error("RegModel",{"set_offset requires a non-null map when register '", + get_full_name(),"' belongs to more than one map."}) + return; + end + + map = get_local_map(map); + + if (map == null) + return; + + map.m_set_reg_offset(this, offset, unmapped); +endfunction + + +// set_parent + +function void uvm_reg::set_parent(uvm_reg_block blk_parent, + uvm_reg_file regfile_parent); + if (m_parent != null) begin + // ToDo: remove register from previous parent + end + m_parent = blk_parent; + m_regfile_parent = regfile_parent; +endfunction + + +// get_parent + +function uvm_reg_block uvm_reg::get_parent(); + return get_block(); +endfunction + + +// get_regfile + +function uvm_reg_file uvm_reg::get_regfile(); + return m_regfile_parent; +endfunction + + +// get_full_name + +function string uvm_reg::get_full_name(); + + if (m_regfile_parent != null) + return {m_regfile_parent.get_full_name(), ".", get_name()}; + + if (m_parent != null) + return {m_parent.get_full_name(), ".", get_name()}; + + return get_name(); +endfunction: get_full_name + + +// add_map + +function void uvm_reg::add_map(uvm_reg_map map); + m_maps[map] = 1; +endfunction + + +// get_maps + +function void uvm_reg::get_maps(ref uvm_reg_map maps[$]); + foreach (m_maps[map]) + maps.push_back(map); +endfunction + + +// get_n_maps + +function int uvm_reg::get_n_maps(); + return m_maps.num(); +endfunction + + +// is_in_map + +function bit uvm_reg::is_in_map(uvm_reg_map map); + if (m_maps.exists(map)) + return 1; + foreach (m_maps[l]) begin + uvm_reg_map local_map = l; + uvm_reg_map parent_map = local_map.get_parent_map(); + + while (parent_map != null) begin + if (parent_map == map) + return 1; + parent_map = parent_map.get_parent_map(); + end + end + return 0; +endfunction + + + +// get_local_map + +function uvm_reg_map uvm_reg::get_local_map(uvm_reg_map map); + if (map == null) + return get_default_map(); + if (m_maps.exists(map)) + return map; + foreach (m_maps[l]) begin + uvm_reg_map local_map=l; + uvm_reg_map parent_map = local_map.get_parent_map(); + + while (parent_map != null) begin + if (parent_map == map) + return local_map; + parent_map = parent_map.get_parent_map(); + end + end + `uvm_warning("RegModel", + {"Register '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'"}) + return null; +endfunction + + + +// get_default_map + +function uvm_reg_map uvm_reg::get_default_map(); + + // if reg is not associated with any map, return ~null~ + if (m_maps.num() == 0) begin + `uvm_warning("RegModel", + {"Register '",get_full_name(),"' is not registered with any map"}) + return null; + end + + // if only one map, choose that + if (m_maps.num() == 1) begin + uvm_reg_map map; + void'(m_maps.first(map)); + return map; + end + + // try to choose one based on default_map in parent blocks. + foreach (m_maps[l]) begin + uvm_reg_map map = l; + uvm_reg_block blk = map.get_parent(); + uvm_reg_map default_map = blk.get_default_map(); + if (default_map != null) begin + uvm_reg_map local_map = get_local_map(default_map); + if (local_map != null) + return local_map; + end + end + + // if that fails, choose the first in this reg's maps + + begin + uvm_reg_map map; + void'(m_maps.first(map)); + return map; + end + +endfunction + + +// get_rights + +function string uvm_reg::get_rights(uvm_reg_map map = null); + + uvm_reg_map_info info; + + map = get_local_map(map); + + if (map == null) + return "RW"; + + info = map.get_reg_map_info(this); + return info.rights; + +endfunction + + + +// get_block + +function uvm_reg_block uvm_reg::get_block(); + get_block = m_parent; +endfunction + + +// get_offset + +function uvm_reg_addr_t uvm_reg::get_offset(uvm_reg_map map = null); + + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + + map = get_local_map(map); + + if (map == null) + return -1; + + map_info = map.get_reg_map_info(this); + + if (map_info.unmapped) begin + `uvm_warning("RegModel", {"Register '",get_name(), + "' is unmapped in map '", + ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}) + return -1; + end + + return map_info.offset; + +endfunction + + +// get_addresses + +function int uvm_reg::get_addresses(uvm_reg_map map=null, ref uvm_reg_addr_t addr[]); + + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + + map = get_local_map(map); + + if (map == null) + return -1; + + map_info = map.get_reg_map_info(this); + + if (map_info.unmapped) begin + `uvm_warning("RegModel", {"Register '",get_name(), + "' is unmapped in map '", + ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}) + return -1; + end + + addr = map_info.addr; + return map.get_n_bytes(); + +endfunction + + +// get_address + +function uvm_reg_addr_t uvm_reg::get_address(uvm_reg_map map = null); + uvm_reg_addr_t addr[]; + void'(get_addresses(map,addr)); + return addr[0]; +endfunction + + +// get_n_bits + +function int unsigned uvm_reg::get_n_bits(); + return m_n_bits; +endfunction + + +// get_n_bytes + +function int unsigned uvm_reg::get_n_bytes(); + return ((m_n_bits-1) / 8) + 1; +endfunction + + +// get_max_size + +function int unsigned uvm_reg::get_max_size(); + return m_max_size; +endfunction: get_max_size + + +// get_fields + +function void uvm_reg::get_fields(ref uvm_reg_field fields[$]); + foreach(m_fields[i]) + fields.push_back(m_fields[i]); +endfunction + + +// get_field_by_name + +function uvm_reg_field uvm_reg::get_field_by_name(string name); + foreach (m_fields[i]) + if (m_fields[i].get_name() == name) + return m_fields[i]; + `uvm_warning("RegModel", {"Unable to locate field '",name, + "' in register '",get_name(),"'"}) + return null; +endfunction + + +// Xget_field_accessX +// +// Returns "WO" if all of the fields in the registers are write-only +// Returns "RO" if all of the fields in the registers are read-only +// Returns "RW" otherwise. + +function string uvm_reg::Xget_fields_accessX(uvm_reg_map map); + bit is_R; + bit is_W; + + foreach(m_fields[i]) begin + case (m_fields[i].get_access(map)) + "RO", + "RC", + "RS": + is_R = 1; + + "WO", + "WOC", + "WOS", + "WO1": + is_W = 1; + + default: + return "RW"; + endcase + + if (is_R && is_W) return "RW"; + end + + case ({is_R, is_W}) + 2'b01: return "WO"; + 2'b10: return "RO"; + endcase + return "RW"; +endfunction + + +//--------- +// COVERAGE +//--------- + + +// include_coverage + +function void uvm_reg::include_coverage(string scope, + uvm_reg_cvr_t models, + uvm_object accessor = null); + uvm_reg_cvr_rsrc_db::set({"uvm_reg::", scope}, + "include_coverage", + models, accessor); +endfunction + + +// build_coverage + +function uvm_reg_cvr_t uvm_reg::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage + + +// add_coverage + +function void uvm_reg::add_coverage(uvm_reg_cvr_t models); + m_has_cover |= models; +endfunction: add_coverage + + +// has_coverage + +function bit uvm_reg::has_coverage(uvm_reg_cvr_t models); + return ((m_has_cover & models) == models); +endfunction: has_coverage + + +// set_coverage + +function uvm_reg_cvr_t uvm_reg::set_coverage(uvm_reg_cvr_t is_on); + if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin + m_cover_on = is_on; + return m_cover_on; + end + + m_cover_on = m_has_cover & is_on; + + return m_cover_on; +endfunction: set_coverage + + +// get_coverage + +function bit uvm_reg::get_coverage(uvm_reg_cvr_t is_on); + if (has_coverage(is_on) == 0) + return 0; + return ((m_cover_on & is_on) == is_on); +endfunction: get_coverage + + + +//--------- +// ACCESS +//--------- + + +// set + +function void uvm_reg::set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + // Split the value into the individual fields + m_fname = fname; + m_lineno = lineno; + + foreach (m_fields[i]) + m_fields[i].set((value >> m_fields[i].get_lsb_pos()) & + ((1 << m_fields[i].get_n_bits()) - 1)); +endfunction: set + + +// predict + +function bit uvm_reg::predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_item rw = new; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.fname = fname; + rw.lineno = lineno; + do_predict(rw, kind, be); + predict = (rw.status == UVM_NOT_OK) ? 0 : 1; +endfunction: predict + + +// do_predict + +function void uvm_reg::do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + + uvm_reg_data_t reg_value = rw.value[0]; + m_fname = rw.fname; + m_lineno = rw.lineno; + +if (rw.status ==UVM_IS_OK ) + rw.status = UVM_IS_OK; + + if (m_is_busy && kind == UVM_PREDICT_DIRECT) begin + `uvm_warning("RegModel", {"Trying to predict value of register '", + get_full_name(),"' while it is being accessed"}) + rw.status = UVM_NOT_OK; + return; + end + + foreach (m_fields[i]) begin + rw.value[0] = (reg_value >> m_fields[i].get_lsb_pos()) & + ((1 << m_fields[i].get_n_bits())-1); + m_fields[i].do_predict(rw, kind, be>>(m_fields[i].get_lsb_pos()/8)); + end + + rw.value[0] = reg_value; + +endfunction: do_predict + + +// get + +function uvm_reg_data_t uvm_reg::get(string fname = "", + int lineno = 0); + // Concatenate the value of the individual fields + // to form the register value + m_fname = fname; + m_lineno = lineno; + + get = 0; + + foreach (m_fields[i]) + get |= m_fields[i].get() << m_fields[i].get_lsb_pos(); +endfunction: get + + +// get_mirrored_value + +function uvm_reg_data_t uvm_reg::get_mirrored_value(string fname = "", + int lineno = 0); + // Concatenate the value of the individual fields + // to form the register value + m_fname = fname; + m_lineno = lineno; + + get_mirrored_value = 0; + + foreach (m_fields[i]) + get_mirrored_value |= m_fields[i].get_mirrored_value() << m_fields[i].get_lsb_pos(); +endfunction: get_mirrored_value + + +// reset + +function void uvm_reg::reset(string kind = "HARD"); + foreach (m_fields[i]) + m_fields[i].reset(kind); + // Put back a key in the semaphore if it is checked out + // in case a thread was killed during an operation + void'(m_atomic.try_get(1)); + m_atomic.put(1); + m_process = null; + Xset_busyX(0); +endfunction: reset + + +// get_reset + +function uvm_reg_data_t uvm_reg::get_reset(string kind = "HARD"); + // Concatenate the value of the individual fields + // to form the register value + get_reset = 0; + + foreach (m_fields[i]) + get_reset |= m_fields[i].get_reset(kind) << m_fields[i].get_lsb_pos(); +endfunction: get_reset + + +// has_reset + +function bit uvm_reg::has_reset(string kind = "HARD", + bit delete = 0); + + has_reset = 0; + foreach (m_fields[i]) begin + has_reset |= m_fields[i].has_reset(kind, delete); + if (!delete && has_reset) + return 1; + end +endfunction: has_reset + + +// set_reset + +function void uvm_reg::set_reset(uvm_reg_data_t value, + string kind = "HARD"); + foreach (m_fields[i]) begin + m_fields[i].set_reset(value >> m_fields[i].get_lsb_pos(), kind); + end +endfunction: set_reset + + +//----------- +// BUS ACCESS +//----------- + +// needs_update + +function bit uvm_reg::needs_update(); + needs_update = 0; + foreach (m_fields[i]) begin + if (m_fields[i].needs_update()) begin + return 1; + end + end +endfunction: needs_update + + +// update + +task uvm_reg::update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t upd; + + status = UVM_IS_OK; + + if (!needs_update()) return; + + // Concatenate the write-to-update values from each field + // Fields are stored in LSB or MSB order + upd = 0; + foreach (m_fields[i]) + upd |= m_fields[i].XupdateX() << m_fields[i].get_lsb_pos(); + + write(status, upd, path, map, parent, prior, extension, fname, lineno); +endtask: update + + + +// write + +task uvm_reg::write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + // create an abstract transaction for this operation + uvm_reg_item rw; + + XatomicX(1); + + set(value); + +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("write_item",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("write_item",,get_full_name()); +`endif + rw.element = this; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + do_write(rw); + + status = rw.status; + + XatomicX(0); + +endtask + + +// do_write + +task uvm_reg::do_write (uvm_reg_item rw); + + uvm_reg_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + uvm_reg_data_t value; + + m_fname = rw.fname; + m_lineno = rw.lineno; + + if (!Xcheck_accessX(rw,map_info)) + return; + + XatomicX(1); + + m_write_in_progress = 1'b1; + + rw.value[0] &= ((1 << m_n_bits)-1); + value = rw.value[0]; + + rw.status = UVM_IS_OK; + + // PRE-WRITE CBS - FIELDS + begin : pre_write_callbacks + uvm_reg_data_t msk; + int lsb; + + foreach (m_fields[i]) begin + uvm_reg_field_cb_iter cbs = new(m_fields[i]); + uvm_reg_field f = m_fields[i]; + lsb = f.get_lsb_pos(); + msk = ((1<> lsb; + f.pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) begin + rw.element = f; + rw.element_kind = UVM_FIELD; + cb.pre_write(rw); + end + + value = (value & ~msk) | (rw.value[0] << lsb); + end + end + rw.element = this; + rw.element_kind = UVM_REG; + rw.value[0] = value; + + // PRE-WRITE CBS - REG + pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_write(rw); + + if (rw.status != UVM_IS_OK) begin + m_write_in_progress = 1'b0; + + XatomicX(0); + + return; + end + + // EXECUTE WRITE... + case (rw.path) + + // ...VIA USER BACKDOOR + UVM_BACKDOOR: begin + uvm_reg_data_t final_val; + uvm_reg_backdoor bkdr = get_backdoor(); + + if (rw.map != null) + rw.local_map = rw.map; + else + rw.local_map = get_default_map(); + + value = rw.value[0]; + + // Mimick the final value after a physical read + rw.kind = UVM_READ; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + + if (rw.status == UVM_NOT_OK) begin + m_write_in_progress = 1'b0; + return; + end + + begin + foreach (m_fields[i]) begin + uvm_reg_data_t field_val; + int lsb = m_fields[i].get_lsb_pos(); + int sz = m_fields[i].get_n_bits(); + field_val = m_fields[i].XpredictX((rw.value[0] >> lsb) & ((1<> lsb) & ((1<> f.get_lsb_pos()) & ((1<> f.get_lsb_pos()) & ((1<> hdl_concat.slices[j].offset; + slice &= (1 << hdl_concat.slices[j].size)-1; + ok &= uvm_hdl_deposit(hdl_concat.slices[j].path, slice); + end + end + end + rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); +endtask + + +// backdoor_read + +task uvm_reg::backdoor_read (uvm_reg_item rw); + rw.status = backdoor_read_func(rw); +endtask + + +// backdoor_read_func + +function uvm_status_e uvm_reg::backdoor_read_func(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + uvm_reg_data_t val; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + val = 0; + foreach (hdl_concat.slices[j]) begin + `uvm_info("RegMem", $sformatf("backdoor_read from %s ", + hdl_concat.slices[j].path),UVM_DEBUG) + + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_read(hdl_concat.slices[j].path,val); + continue; + end + begin + uvm_reg_data_t slice; + int k = hdl_concat.slices[j].offset; + + ok &= uvm_hdl_read(hdl_concat.slices[j].path, slice); + + repeat (hdl_concat.slices[j].size) begin + val[k++] = slice[0]; + slice >>= 1; + end + end + end + + val &= (1 << m_n_bits)-1; + + if (i == 0) + rw.value[0] = val; + + if (val != rw.value[0]) begin + `uvm_error("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", + get_full_name(), + rw.value[0], uvm_hdl_concat2string(paths[0]), + val, uvm_hdl_concat2string(paths[i]))) + return UVM_NOT_OK; + end + `uvm_info("RegMem", + $sformatf("returned backdoor value 0x%0x",rw.value[0]),UVM_DEBUG) + + end + + rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; + return rw.status; +endfunction + + +// poke + +task uvm_reg::poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + + m_fname = fname; + m_lineno = lineno; + + + if (bkdr == null && !has_hdl_path(kind)) begin + `uvm_error("RegModel", + {"No backdoor access available to poke register '",get_full_name(),"'"}) + status = UVM_NOT_OK; + return; + end + + if (!m_is_locked_by_field) + XatomicX(1); + + // create an abstract transaction for this operation +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("reg_poke_item",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("reg_poke_item",,get_full_name()); +`endif + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.bd_kind = kind; + rw.value[0] = value & ((1 << m_n_bits)-1); + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + + status = rw.status; + + `uvm_info("RegModel", $sformatf("Poked register \"%s\": 'h%h", + get_full_name(), value),UVM_HIGH) + + do_predict(rw, UVM_PREDICT_WRITE); + + if (!m_is_locked_by_field) + XatomicX(0); +endtask: poke + + +// peek + +task uvm_reg::peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + + m_fname = fname; + m_lineno = lineno; + + if (bkdr == null && !has_hdl_path(kind)) begin + `uvm_error("RegModel", + $sformatf("No backdoor access available to peek register \"%s\"", + get_full_name())) + status = UVM_NOT_OK; + return; + end + + if(!m_is_locked_by_field) + XatomicX(1); + + // create an abstract transaction for this operation +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("mem_peek_item",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("mem_peek_item",,get_full_name()); +`endif + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_REG; + rw.kind = UVM_READ; + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + + status = rw.status; + value = rw.value[0]; + + `uvm_info("RegModel", $sformatf("Peeked register \"%s\": 'h%h", + get_full_name(), value),UVM_HIGH) + + do_predict(rw, UVM_PREDICT_READ); + + if (!m_is_locked_by_field) + XatomicX(0); +endtask: peek + + +// do_check +function bit uvm_reg::do_check(input uvm_reg_data_t expected, + input uvm_reg_data_t actual, + uvm_reg_map map); + + uvm_reg_data_t valid_bits_mask = 0; // elements 1 indicating bit we care about + + foreach(m_fields[i]) begin + string acc = m_fields[i].get_access(map); + acc = acc.substr(0, 1); + if (!(m_fields[i].get_compare() == UVM_NO_CHECK ||acc == "WO")) begin + valid_bits_mask |= ((1 << m_fields[i].get_n_bits())-1)<< m_fields[i].get_lsb_pos(); + end + end + + if ((actual&valid_bits_mask) === (expected&valid_bits_mask)) return 1; + + `uvm_error("RegModel", $sformatf("Register \"%s\" value read from DUT (0x%h) does not match mirrored value (0x%h) (valid bit mask = 0x%h)", + get_full_name(), actual, expected,valid_bits_mask)) + + foreach(m_fields[i]) begin + string acc = m_fields[i].get_access(map); + acc = acc.substr(0, 1); + if (!(m_fields[i].get_compare() == UVM_NO_CHECK || + acc == "WO")) begin + uvm_reg_data_t mask = ((1 << m_fields[i].get_n_bits())-1); + uvm_reg_data_t val = actual >> m_fields[i].get_lsb_pos() & mask; + uvm_reg_data_t exp = expected >> m_fields[i].get_lsb_pos() & mask; + + if (val !== exp) begin + `uvm_info("RegModel", + $sformatf("Field %s (%s[%0d:%0d]) mismatch read=%0d'h%0h mirrored=%0d'h%0h ", + m_fields[i].get_name(), get_full_name(), + m_fields[i].get_lsb_pos() + m_fields[i].get_n_bits() - 1, + m_fields[i].get_lsb_pos(), + m_fields[i].get_n_bits(), val, + m_fields[i].get_n_bits(), exp), + UVM_NONE) + end + end + end + + return 0; +endfunction + + +// mirror + +task uvm_reg::mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t v; + uvm_reg_data_t exp; + uvm_reg_backdoor bkdr = get_backdoor(); + + XatomicX(1); + m_fname = fname; + m_lineno = lineno; + + + if (path == UVM_DEFAULT_DOOR) + path = m_parent.get_default_door(); + + if (path == UVM_BACKDOOR && (bkdr != null || has_hdl_path())) + map = uvm_reg_map::backdoor(); + else + map = get_local_map(map); + + if (map == null) + return; + + // Remember what we think the value is before it gets updated + if (check == UVM_CHECK) + exp = get_mirrored_value(); + + XreadX(status, v, path, map, parent, prior, extension, fname, lineno); + + if (status == UVM_NOT_OK) begin + XatomicX(0); + return; + end + + if (check == UVM_CHECK) void'(do_check(exp, v, map)); + + XatomicX(0); +endtask: mirror + + +// XatomicX + +task uvm_reg::XatomicX(bit on); + process m_reg_process; + m_reg_process=process::self(); + + if (on) begin + if (m_reg_process == m_process) + return; + m_atomic.get(1); + m_process = m_reg_process; + end + else begin + // Maybe a key was put back in by a spurious call to reset() + void'(m_atomic.try_get(1)); + m_atomic.put(1); + m_process = null; + end +endtask: XatomicX + + +//------------- +// STANDARD OPS +//------------- + +// convert2string + +function string uvm_reg::convert2string(); + string res_str; + string t_str; + bit with_debug_info; + + string prefix; + + $sformat(convert2string, "Register %s -- %0d bytes, mirror value:'h%h", + get_full_name(), get_n_bytes(),get()); + + if (m_maps.num()==0) + convert2string = {convert2string, " (unmapped)\n"}; + else + convert2string = {convert2string, "\n"}; + foreach (m_maps[map]) begin + uvm_reg_map parent_map = map; + int unsigned offset; + while (parent_map != null) begin + uvm_reg_map this_map = parent_map; + parent_map = this_map.get_parent_map(); + offset = parent_map == null ? this_map.get_base_addr(UVM_NO_HIER) : + parent_map.get_submap_offset(this_map); + prefix = {prefix, " "}; + begin + uvm_endianness_e e = this_map.get_endian(); + $sformat(convert2string, + "%sMapped in '%s' -- %d bytes, %s, offset 'h%0h\n", + prefix, this_map.get_full_name(), this_map.get_n_bytes(), + e.name(), offset); + end + end + end + prefix = " "; + foreach(m_fields[i]) begin + $sformat(convert2string, "%s\n%s", convert2string, + m_fields[i].convert2string()); + end + + if (m_read_in_progress == 1'b1) begin + if (m_fname != "" && m_lineno != 0) + $sformat(res_str, "%s:%0d ",m_fname, m_lineno); + convert2string = {convert2string, "\n", res_str, + "currently executing read method"}; + end + if ( m_write_in_progress == 1'b1) begin + if (m_fname != "" && m_lineno != 0) + $sformat(res_str, "%s:%0d ",m_fname, m_lineno); + convert2string = {convert2string, "\n", res_str, + "currently executing write method"}; + end + +endfunction: convert2string + + +// do_print + +function void uvm_reg::do_print (uvm_printer printer); + uvm_reg_field f[$]; + super.do_print(printer); + get_fields(f); + foreach(f[i]) printer.print_generic(f[i].get_name(),f[i].get_type_name(),-2,f[i].convert2string()); +endfunction + + + +// clone + +function uvm_object uvm_reg::clone(); + `uvm_fatal("RegModel","RegModel registers cannot be cloned") + return null; +endfunction + +// do_copy + +function void uvm_reg::do_copy(uvm_object rhs); + `uvm_fatal("RegModel","RegModel registers cannot be copied") +endfunction + + +// do_compare + +function bit uvm_reg::do_compare (uvm_object rhs, + uvm_comparer comparer); + `uvm_warning("RegModel","RegModel registers cannot be compared") + return 0; +endfunction + + +// do_pack + +function void uvm_reg::do_pack (uvm_packer packer); + `uvm_warning("RegModel","RegModel registers cannot be packed") +endfunction + + +// do_unpack + +function void uvm_reg::do_unpack (uvm_packer packer); + `uvm_warning("RegModel","RegModel registers cannot be unpacked") +endfunction diff --git a/test_regress/t/t_uvm/reg/uvm_reg_adapter.svh b/test_regress/t/t_uvm/reg/uvm_reg_adapter.svh new file mode 100644 index 0000000000..50a2054fa8 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_adapter.svh @@ -0,0 +1,259 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2015 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. +// ------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Classes for Adapting Between Register and Bus Operations +// +// This section defines classes used to convert transaction streams between +// generic register address/data reads and writes and physical bus accesses. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_reg_adapter +// +// This class defines an interface for converting between +// and a specific bus transaction. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 19.2.1.1 +virtual class uvm_reg_adapter extends uvm_object; + + + `uvm_object_abstract_utils(uvm_reg_adapter) + + + // Function -- NODOCS -- new + // + // Create a new instance of this type, giving it the optional ~name~. + + // @uvm-ieee 1800.2-2017 auto 19.2.1.2.1 + function new(string name=""); + super.new(name); + endfunction + + + // Variable -- NODOCS -- supports_byte_enable + // + // Set this bit in extensions of this class if the bus protocol supports + // byte enables. + + bit supports_byte_enable; + + + // Variable -- NODOCS -- provides_responses + // + // Set this bit in extensions of this class if the bus driver provides + // separate response items. + + bit provides_responses; + + + // Variable -- NODOCS -- parent_sequence + // + // Set this member in extensions of this class if the bus driver requires + // bus items be executed via a particular sequence base type. The sequence + // assigned to this member must implement do_clone(). + + uvm_sequence_base parent_sequence; + + + // Function -- NODOCS -- reg2bus + // + // Extensions of this class ~must~ implement this method to convert the specified + // to a corresponding subtype that defines the bus + // transaction. + // + // The method must allocate a new bus-specific , + // assign its members from + // the corresponding members from the given generic ~rw~ bus operation, then + // return it. + + // @uvm-ieee 1800.2-2017 auto 19.2.1.2.5 + pure virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); + + + // Function -- NODOCS -- bus2reg + // + // Extensions of this class ~must~ implement this method to copy members + // of the given bus-specific ~bus_item~ to corresponding members of the provided + // ~bus_rw~ instance. Unlike , the resulting transaction + // is not allocated from scratch. This is to accommodate applications + // where the bus response must be returned in the original request. + + // @uvm-ieee 1800.2-2017 auto 19.2.1.2.6 + pure virtual function void bus2reg(uvm_sequence_item bus_item, + ref uvm_reg_bus_op rw); + + + local uvm_reg_item m_item; + + + // @uvm-ieee 1800.2-2017 auto 19.2.1.2.7 + virtual function uvm_reg_item get_item(); + return m_item; + endfunction + + virtual function void m_set_item(uvm_reg_item item); + m_item = item; + endfunction +endclass + + +//------------------------------------------------------------------------------ +// Group -- NODOCS -- Example +// +// The following example illustrates how to implement a RegModel-BUS adapter class +// for the APB bus protocol. +// +//|class rreg2apb_adapter extends uvm_reg_adapter; +//| `uvm_object_utils(reg2apb_adapter) +//| +//| function new(string name="reg2apb_adapter"); +//| super.new(name); +//| +//| endfunction +//| +//| virtual function uvm_sequence_item reg2bus(uvm_reg_bus_op rw); +//| apb_item apb = apb_item::type_id::create("apb_item"); +//| apb.op = (rw.kind == UVM_READ) ? apb::READ : apb::WRITE; +//| apb.addr = rw.addr; +//| apb.data = rw.data; +//| return apb; +//| endfunction +//| +//| virtual function void bus2reg(uvm_sequencer_item bus_item, +//| uvm_reg_bus_op rw); +//| apb_item apb; +//| if (!$cast(apb,bus_item)) begin +//| `uvm_fatal("CONVERT_APB2REG","Bus item is not of type apb_item") +//| end +//| rw.kind = apb.op==apb::READ ? UVM_READ : UVM_WRITE; +//| rw.addr = apb.addr; +//| rw.data = apb.data; +//| rw.status = UVM_IS_OK; +//| endfunction +//| +//|endclass +// +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_reg_tlm_adapter +// +// For converting between and items. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 19.2.2.1 +class uvm_reg_tlm_adapter extends uvm_reg_adapter; + + `uvm_object_utils(uvm_reg_tlm_adapter) + + function new(string name = "uvm_reg_tlm_adapter"); + super.new(name); + endfunction + + // Function -- NODOCS -- reg2bus + // + // Converts a struct to a item. + + // @uvm-ieee 1800.2-2017 auto 19.2.2.2.1 + virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); + +`ifdef VERILATOR + uvm_tlm_gp gp = uvm_tlm_gp::type_id_create("tlm_gp",, this.get_full_name()); +`else + uvm_tlm_gp gp = uvm_tlm_gp::type_id::create("tlm_gp",, this.get_full_name()); +`endif + int nbytes = (rw.n_bits-1)/8+1; + uvm_reg_addr_t addr=rw.addr; + + if (rw.kind == UVM_WRITE) + gp.set_command(UVM_TLM_WRITE_COMMAND); + else + gp.set_command(UVM_TLM_READ_COMMAND); + + gp.set_address(addr); + + gp.m_byte_enable = new [nbytes]; + gp.m_byte_enable_length = nbytes; + + gp.set_streaming_width (nbytes); + + gp.m_data = new [gp.get_streaming_width()]; + gp.m_length = nbytes; + + for (int i = 0; i < nbytes; i++) begin + gp.m_data[i] = rw.data[i*8+:8]; + gp.m_byte_enable[i] = (i > nbytes) ? 8'h00 : (rw.byte_en[i] ? 8'hFF : 8'h00); + end + + return gp; + + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 19.2.2.2.2 + virtual function void bus2reg(uvm_sequence_item bus_item, + ref uvm_reg_bus_op rw); + + uvm_tlm_gp gp; + int nbytes; + + if (bus_item == null) + `uvm_fatal("REG/NULL_ITEM","bus2reg: bus_item argument is null") + + if (!$cast(gp,bus_item)) begin + `uvm_error("WRONG_TYPE","Provided bus_item is not of type uvm_tlm_gp") + return; + end + + if (gp.get_command() == UVM_TLM_WRITE_COMMAND) + rw.kind = UVM_WRITE; + else + rw.kind = UVM_READ; + + rw.addr = gp.get_address(); + + rw.byte_en = 0; + foreach (gp.m_byte_enable[i]) + rw.byte_en[i] = gp.m_byte_enable[i]; + + rw.data = 0; + foreach (gp.m_data[i]) + rw.data[i*8+:8] = gp.m_data[i]; + + rw.status = (gp.is_response_ok()) ? UVM_IS_OK : UVM_NOT_OK; + + + endfunction + +endclass diff --git a/test_regress/t/t_uvm/reg/uvm_reg_backdoor.svh b/test_regress/t/t_uvm/reg/uvm_reg_backdoor.svh new file mode 100644 index 0000000000..d8f49317d2 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_backdoor.svh @@ -0,0 +1,266 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2015-2018 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. +// ------------------------------------------------------------- +// + +typedef class uvm_reg_cbs; + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_backdoor +// +// Base class for user-defined back-door register and memory access. +// +// This class can be extended by users to provide user-specific back-door access +// to registers and memories that are not implemented in pure SystemVerilog +// or that are not accessible using the default DPI backdoor mechanism. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 19.5.1 +virtual class uvm_reg_backdoor extends uvm_object; + + + `uvm_object_abstract_utils(uvm_reg_backdoor) + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.1 + function new(string name = ""); + super.new(name); + endfunction: new + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.2 + protected task do_pre_read(uvm_reg_item rw); + pre_read(rw); + `uvm_do_obj_callbacks(uvm_reg_backdoor, uvm_reg_cbs, this, + pre_read(rw)) + endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.3 + protected task do_post_read(uvm_reg_item rw); + uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); + for(uvm_reg_cbs cb = iter.last(); cb != null; cb=iter.prev()) + cb.decode(rw.value); + `uvm_do_obj_callbacks(uvm_reg_backdoor,uvm_reg_cbs,this,post_read(rw)) + post_read(rw); + endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.4 + protected task do_pre_write(uvm_reg_item rw); + uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); + pre_write(rw); + `uvm_do_obj_callbacks(uvm_reg_backdoor,uvm_reg_cbs,this,pre_write(rw)) + for(uvm_reg_cbs cb = iter.first(); cb != null; cb = iter.next()) + cb.encode(rw.value); + endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.5 + protected task do_post_write(uvm_reg_item rw); + `uvm_do_obj_callbacks(uvm_reg_backdoor,uvm_reg_cbs,this,post_write(rw)) + post_write(rw); + endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.6 + extern virtual task write(uvm_reg_item rw); + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.7 + extern virtual task read(uvm_reg_item rw); + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.8 + extern virtual function void read_func(uvm_reg_item rw); + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.9 + extern virtual function bit is_auto_updated(uvm_reg_field field); + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.10 + extern virtual local task wait_for_change(uvm_object element); + + + /*local*/ extern function void start_update_thread(uvm_object element); + /*local*/ extern function void kill_update_thread(uvm_object element); + /*local*/ extern function bit has_update_threads(); + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.11 + virtual task pre_read(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.12 + virtual task post_read(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.13 + virtual task pre_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.5.2.14 + virtual task post_write(uvm_reg_item rw); endtask + + + string fname; + int lineno; + +`ifdef UVM_USE_PROCESS_CONTAINER + local process_container_c m_update_thread[uvm_object]; +`else + local process m_update_thread[uvm_object]; +`endif + + `uvm_register_cb(uvm_reg_backdoor, uvm_reg_cbs) + + +endclass: uvm_reg_backdoor + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + + +// is_auto_updated + +function bit uvm_reg_backdoor::is_auto_updated(uvm_reg_field field); + return 0; +endfunction + + +// wait_for_change + +task uvm_reg_backdoor::wait_for_change(uvm_object element); + `uvm_fatal("RegModel", "uvm_reg_backdoor::wait_for_change() method has not been overloaded") +endtask + + +// start_update_thread + +function void uvm_reg_backdoor::start_update_thread(uvm_object element); + uvm_reg rg; + if (this.m_update_thread.exists(element)) begin + this.kill_update_thread(element); + end + if (!$cast(rg,element)) + return; // only regs supported at this time + + fork + begin + uvm_reg_field fields[$]; + +`ifdef UVM_USE_PROCESS_CONTAINER + this.m_update_thread[element] = new(process::self()); +`else + this.m_update_thread[element] = process::self(); +`endif + + rg.get_fields(fields); + forever begin + uvm_status_e status; + uvm_reg_data_t val; + uvm_reg_item r_item = new("bd_r_item"); + r_item.element = rg; + r_item.element_kind = UVM_REG; + this.read(r_item); + val = r_item.value[0]; + if (r_item.status != UVM_IS_OK) begin + `uvm_error("RegModel", $sformatf("Backdoor read of register '%s' failed.", + rg.get_name())) + end + foreach (fields[i]) begin + if (this.is_auto_updated(fields[i])) begin + r_item.value[0] = (val >> fields[i].get_lsb_pos()) & + ((1 << fields[i].get_n_bits())-1); + fields[i].do_predict(r_item); + end + end + this.wait_for_change(element); + end + end + join_none +endfunction + + +// kill_update_thread + +function void uvm_reg_backdoor::kill_update_thread(uvm_object element); + if (this.m_update_thread.exists(element)) begin + +`ifdef UVM_USE_PROCESS_CONTAINER + this.m_update_thread[element].p.kill(); +`else + this.m_update_thread[element].kill(); +`endif + + this.m_update_thread.delete(element); + end +endfunction + + +// has_update_threads + +function bit uvm_reg_backdoor::has_update_threads(); + return this.m_update_thread.num() > 0; +endfunction + + +// write + +task uvm_reg_backdoor::write(uvm_reg_item rw); + `uvm_fatal("RegModel", "uvm_reg_backdoor::write() method has not been overloaded") +endtask + + +// read + +task uvm_reg_backdoor::read(uvm_reg_item rw); + do_pre_read(rw); + read_func(rw); + do_post_read(rw); +endtask + + +// read_func + +function void uvm_reg_backdoor::read_func(uvm_reg_item rw); + `uvm_fatal("RegModel", "uvm_reg_backdoor::read_func() method has not been overloaded") + rw.status = UVM_NOT_OK; +endfunction diff --git a/test_regress/t/t_uvm/reg/uvm_reg_block.svh b/test_regress/t/t_uvm/reg/uvm_reg_block.svh new file mode 100644 index 0000000000..d141af7f09 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_block.svh @@ -0,0 +1,2329 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + + + + +// @uvm-ieee 1800.2-2017 auto 18.1.1 +class uvm_reg_block extends uvm_object; + + + `uvm_object_utils(uvm_reg_block) + + + local uvm_reg_block parent; + + local static bit m_roots[uvm_reg_block]; + local static int unsigned m_root_names[string]; + + local int unsigned blks[uvm_reg_block]; + local int unsigned regs[uvm_reg]; + local int unsigned vregs[uvm_vreg]; + local int unsigned mems[uvm_mem]; + local bit maps[uvm_reg_map]; + + // Variable -- NODOCS -- default_path + // Default access path for the registers and memories in this block. +`ifdef UVM_ENABLE_DEPRECATED_API + uvm_door_e default_path = UVM_DEFAULT_DOOR; +`else + local uvm_door_e default_path = UVM_DEFAULT_DOOR; +`endif + + local string default_hdl_path = "RTL"; + local uvm_reg_backdoor backdoor; + local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; + local string root_hdl_paths[string]; + + local bit locked; + + local int has_cover; + local int cover_on; + local string fname; + local int lineno; + + local event m_uvm_lock_model_complete; + + local static int id; + + //---------------------- + // Group -- NODOCS -- Initialization + //---------------------- + + // Function -- NODOCS -- new + // + // Create a new instance and type-specific configuration + // + // Creates an instance of a block abstraction class with the specified + // name. + // + // ~has_coverage~ specifies which functional coverage models are present in + // the extension of the block abstraction class. + // Multiple functional coverage models may be specified by adding their + // symbolic names, as defined by the type. + // + extern function new(string name="", int has_coverage=UVM_NO_COVERAGE); + + + // Function -- NODOCS -- configure + // + // Instance-specific configuration + // + // Specify the parent block of this block. + // A block without parent is a root block. + // + // If the block file corresponds to a hierarchical RTL structure, + // its contribution to the HDL path is specified as the ~hdl_path~. + // Otherwise, the block does not correspond to a hierarchical RTL + // structure (e.g. it is physically flattened) and does not contribute + // to the hierarchical HDL path of any contained registers or memories. + // + extern function void configure(uvm_reg_block parent=null, + string hdl_path=""); + + + // Function -- NODOCS -- create_map + // + // Create an address map in this block + // + // Create an address map with the specified ~name~, then + // configures it with the following properties. + // + // base_addr - the base address for the map. All registers, memories, + // and sub-blocks within the map will be at offsets to this + // address + // + // n_bytes - the byte-width of the bus on which this map is used + // + // endian - the endian format. See for possible + // values + // + // byte_addressing - specifies whether consecutive addresses refer are 1 byte + // apart (TRUE) or ~n_bytes~ apart (FALSE). Default is TRUE. + // + //| APB = create_map("APB", 0, 1, UVM_LITTLE_ENDIAN, 1); + // + extern virtual function uvm_reg_map create_map(string name, + uvm_reg_addr_t base_addr, + int unsigned n_bytes, + uvm_endianness_e endian, + bit byte_addressing = 1); + + + // Function -- NODOCS -- check_data_width + // + // Check that the specified data width (in bits) is less than + // or equal to the value of `UVM_REG_DATA_WIDTH + // + // This method is designed to be called by a static initializer + // + //| class my_blk extends uvm_reg_block; + //| local static bit m_data_width = check_data_width(356); + //| ... + //| endclass + // + extern protected static function bit check_data_width(int unsigned width); + + + + // Function -- NODOCS -- set_default_map + // + // Defines the default address map + // + // Set the specified address map as the for this + // block. The address map must be a map of this address block. + // + extern function void set_default_map (uvm_reg_map map); + + + // Variable -- NODOCS -- default_map + // + // Default address map + // + // Default address map for this block, to be used when no + // address map is specified for a register operation and that + // register is accessible from more than one address map. + // + // It is also the implicit address map for a block with a single, + // unnamed address map because it has only one physical interface. + // + uvm_reg_map default_map; + + extern function uvm_reg_map get_default_map (); + + extern virtual function void set_parent(uvm_reg_block parent); + + /*local*/ extern function void add_block (uvm_reg_block blk); + /*local*/ extern function void add_map (uvm_reg_map map); + /*local*/ extern function void add_reg (uvm_reg rg); + /*local*/ extern function void add_vreg (uvm_vreg vreg); + /*local*/ extern function void add_mem (uvm_mem mem); + + + // Function -- NODOCS -- lock_model + // + // Lock a model and build the address map. + // + // Recursively lock an entire register model + // and build the address maps to enable the + // and + // methods. + // + // Once locked, no further structural changes, + // such as adding registers or memories, + // can be made. + extern virtual function void lock_model(); + + // brings back the register mode to a state before lock_model() so that a subsequent lock_model() can be issued + virtual function void unlock_model(); + bit s[uvm_reg_block]=m_roots; + m_roots.delete(); + + foreach (blks[blk_]) + blk_.unlock_model(); + + m_roots=s; + foreach(m_roots[b]) + m_roots[b]=0; + + locked=0; + endfunction + + virtual task wait_for_lock(); + @m_uvm_lock_model_complete; + endtask + + + // Function -- NODOCS -- is_locked + // + // Return TRUE if the model is locked. + // + extern function bit is_locked(); + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + + // Function -- NODOCS -- get_name + // + // Get the simple name + // + // Return the simple object name of this block. + // + + + // Function -- NODOCS -- get_full_name + // + // Get the hierarchical name + // + // Return the hierarchal name of this block. + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + // Function -- NODOCS -- get_parent + // + // Get the parent block + // + // If this a top-level block, returns ~null~. + // + extern virtual function uvm_reg_block get_parent(); + + + // Function -- NODOCS -- get_root_blocks + // + // Get the all root blocks + // + // Returns an array of all root blocks in the simulation. + // + extern static function void get_root_blocks(ref uvm_reg_block blks[$]); + + + // Function -- NODOCS -- find_blocks + // + // Find the blocks whose hierarchical names match the + // specified ~name~ glob. + // If a ~root~ block is specified, the name of the blocks are + // relative to that block, otherwise they are absolute. + // + // Returns the number of blocks found. + // + extern static function int find_blocks(input string name, + ref uvm_reg_block blks[$], + input uvm_reg_block root = null, + input uvm_object accessor = null); + + + // Function -- NODOCS -- find_block + // + // Find the first block whose hierarchical names match the + // specified ~name~ glob. + // If a ~root~ block is specified, the name of the blocks are + // relative to that block, otherwise they are absolute. + // + // Returns the first block found or ~null~ otherwise. + // A warning is issued if more than one block is found. + // + extern static function uvm_reg_block find_block(input string name, + input uvm_reg_block root = null, + input uvm_object accessor = null); + + + // Function -- NODOCS -- get_blocks + // + // Get the sub-blocks + // + // Get the blocks instantiated in this blocks. + // If ~hier~ is TRUE, recursively includes any sub-blocks. + // + extern virtual function void get_blocks (ref uvm_reg_block blks[$], + input uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_maps + // + // Get the address maps + // + // Get the address maps instantiated in this block. + // + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + + + // Function -- NODOCS -- get_registers + // + // Get the registers + // + // Get the registers instantiated in this block. + // If ~hier~ is TRUE, recursively includes the registers + // in the sub-blocks. + // + // Note that registers may be located in different and/or multiple + // address maps. To get the registers in a specific address map, + // use the method. + // + extern virtual function void get_registers (ref uvm_reg regs[$], + input uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_fields + // + // Get the fields + // + // Get the fields in the registers instantiated in this block. + // If ~hier~ is TRUE, recursively includes the fields of the registers + // in the sub-blocks. + // + extern virtual function void get_fields (ref uvm_reg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_memories + // + // Get the memories + // + // Get the memories instantiated in this block. + // If ~hier~ is TRUE, recursively includes the memories + // in the sub-blocks. + // + // Note that memories may be located in different and/or multiple + // address maps. To get the memories in a specific address map, + // use the method. + // + extern virtual function void get_memories (ref uvm_mem mems[$], + input uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_virtual_registers + // + // Get the virtual registers + // + // Get the virtual registers instantiated in this block. + // If ~hier~ is TRUE, recursively includes the virtual registers + // in the sub-blocks. + // + extern virtual function void get_virtual_registers(ref uvm_vreg regs[$], + input uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_virtual_fields + // + // Get the virtual fields + // + // Get the virtual fields from the virtual registers instantiated + // in this block. + // If ~hier~ is TRUE, recursively includes the virtual fields + // in the virtual registers in the sub-blocks. + // + extern virtual function void get_virtual_fields (ref uvm_vreg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_block_by_name + // + // Finds a sub-block with the specified simple name. + // + // The name is the simple name of the block, not a hierarchical name. + // relative to this block. + // If no block with that name is found in this block, the sub-blocks + // are searched for a block of that name and the first one to be found + // is returned. + // + // If no blocks are found, returns ~null~. + // + extern virtual function uvm_reg_block get_block_by_name (string name); + + + // Function -- NODOCS -- get_map_by_name + // + // Finds an address map with the specified simple name. + // + // The name is the simple name of the address map, not a hierarchical name. + // relative to this block. + // If no map with that name is found in this block, the sub-blocks + // are searched for a map of that name and the first one to be found + // is returned. + // + // If no address maps are found, returns ~null~. + // + extern virtual function uvm_reg_map get_map_by_name (string name); + + + // Function -- NODOCS -- get_reg_by_name + // + // Finds a register with the specified simple name. + // + // The name is the simple name of the register, not a hierarchical name. + // relative to this block. + // If no register with that name is found in this block, the sub-blocks + // are searched for a register of that name and the first one to be found + // is returned. + // + // If no registers are found, returns ~null~. + // + extern virtual function uvm_reg get_reg_by_name (string name); + + + // Function -- NODOCS -- get_field_by_name + // + // Finds a field with the specified simple name. + // + // The name is the simple name of the field, not a hierarchical name. + // relative to this block. + // If no field with that name is found in this block, the sub-blocks + // are searched for a field of that name and the first one to be found + // is returned. + // + // If no fields are found, returns ~null~. + // + extern virtual function uvm_reg_field get_field_by_name (string name); + + + // Function -- NODOCS -- get_mem_by_name + // + // Finds a memory with the specified simple name. + // + // The name is the simple name of the memory, not a hierarchical name. + // relative to this block. + // If no memory with that name is found in this block, the sub-blocks + // are searched for a memory of that name and the first one to be found + // is returned. + // + // If no memories are found, returns ~null~. + // + extern virtual function uvm_mem get_mem_by_name (string name); + + + // Function -- NODOCS -- get_vreg_by_name + // + // Finds a virtual register with the specified simple name. + // + // The name is the simple name of the virtual register, + // not a hierarchical name. + // relative to this block. + // If no virtual register with that name is found in this block, + // the sub-blocks are searched for a virtual register of that name + // and the first one to be found is returned. + // + // If no virtual registers are found, returns ~null~. + // + extern virtual function uvm_vreg get_vreg_by_name (string name); + + + // Function -- NODOCS -- get_vfield_by_name + // + // Finds a virtual field with the specified simple name. + // + // The name is the simple name of the virtual field, + // not a hierarchical name. + // relative to this block. + // If no virtual field with that name is found in this block, + // the sub-blocks are searched for a virtual field of that name + // and the first one to be found is returned. + // + // If no virtual fields are found, returns ~null~. + // + extern virtual function uvm_vreg_field get_vfield_by_name (string name); + + + //---------------- + // Group -- NODOCS -- Coverage + //---------------- + + + // Function -- NODOCS -- build_coverage + // + // Check if all of the specified coverage model must be built. + // + // Check which of the specified coverage model must be built + // in this instance of the block abstraction class, + // as specified by calls to . + // + // Models are specified by adding the symbolic value of individual + // coverage model as defined in . + // Returns the sum of all coverage models to be built in the + // block model. + // + extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models); + + + // Function -- NODOCS -- add_coverage + // + // Specify that additional coverage models are available. + // + // Add the specified coverage model to the coverage models + // available in this class. + // Models are specified by adding the symbolic value of individual + // coverage model as defined in . + // + // This method shall be called only in the constructor of + // subsequently derived classes. + // + extern virtual protected function void add_coverage(uvm_reg_cvr_t models); + + + // Function -- NODOCS -- has_coverage + // + // Check if block has coverage model(s) + // + // Returns TRUE if the block abstraction class contains a coverage model + // for all of the models specified. + // Models are specified by adding the symbolic value of individual + // coverage model as defined in . + // + extern virtual function bit has_coverage(uvm_reg_cvr_t models); + + + // Function -- NODOCS -- set_coverage + // + // Turns on coverage measurement. + // + // Turns the collection of functional coverage measurements on or off + // for this block and all blocks, registers, fields and memories within it. + // The functional coverage measurement is turned on for every + // coverage model specified using symbolic + // identifiers. + // Multiple functional coverage models can be specified by adding + // the functional coverage model identifiers. + // All other functional coverage models are turned off. + // Returns the sum of all functional + // coverage models whose measurements were previously on. + // + // This method can only control the measurement of functional + // coverage models that are present in the various abstraction classes, + // then enabled during construction. + // See the method to identify + // the available functional coverage models. + // + extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on); + + + // Function -- NODOCS -- get_coverage + // + // Check if coverage measurement is on. + // + // Returns TRUE if measurement for all of the specified functional + // coverage models are currently on. + // Multiple functional coverage models can be specified by adding the + // functional coverage model identifiers. + // + // See for more details. + // + extern virtual function bit get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL); + + + // Function -- NODOCS -- sample + // + // Functional coverage measurement method + // + // This method is invoked by the block abstraction class + // whenever an address within one of its address map + // is successfully read or written. + // The specified offset is the offset within the block, + // not an absolute address. + // + // Empty by default, this method may be extended by the + // abstraction class generator to perform the required sampling + // in any provided functional coverage model. + // + protected virtual function void sample(uvm_reg_addr_t offset, + bit is_read, + uvm_reg_map map); + endfunction + + + // Function -- NODOCS -- sample_values + // + // Functional coverage measurement method for field values + // + // This method is invoked by the user + // or by the method of the parent block + // to trigger the sampling + // of the current field values in the + // block-level functional coverage model. + // It recursively invokes the + // and methods + // in the blocks and registers in this block. + // + // This method may be extended by the + // abstraction class generator to perform the required sampling + // in any provided field-value functional coverage model. + // If this method is extended, it MUST call super.sample_values(). + // + extern virtual function void sample_values(); + + /*local*/ extern function void XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + + + //-------------- + // Group -- NODOCS -- Access + //-------------- + + // Function -- NODOCS -- get_default_door + + extern virtual function uvm_door_e get_default_door(); + + // Function -- NODOCS -- set_default_door + + extern virtual function void set_default_door(uvm_door_e door); + +`ifdef UVM_ENABLE_DEPRECATED_API + // Function -- NODOCS -- get_default_path + // + // Default access path + // + // Returns the default access path for this block. + // + extern virtual function uvm_path_e get_default_path(); +`endif + + // Function -- NODOCS -- reset + // + // Reset the mirror for this block. + // + // Sets the mirror value of all registers in the block and sub-blocks + // to the reset value corresponding to the specified reset event. + // See for more details. + // Does not actually set the value of the registers in the design, + // only the values mirrored in their corresponding mirror. + // + extern virtual function void reset(string kind = "HARD"); + + + // Function -- NODOCS -- needs_update + // + // Check if DUT registers need to be written + // + // If a mirror value has been modified in the abstraction model + // without actually updating the actual register + // (either through randomization or via the method, + // the mirror and state of the registers are outdated. + // The corresponding registers in the DUT need to be updated. + // + // This method returns TRUE if the state of at least one register in + // the block or sub-blocks needs to be updated to match the mirrored + // values. + // The mirror values, or actual content of registers, are not modified. + // For additional information, see method. + // + extern virtual function bit needs_update(); + + + // Task -- NODOCS -- update + // + // Batch update of register. + // + // Using the minimum number of write operations, updates the registers + // in the design to match the mirrored values in this block and sub-blocks. + // The update can be performed using the physical + // interfaces (front-door access) or back-door accesses. + // This method performs the reverse operation of . + // + extern virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // Task -- NODOCS -- mirror + // + // Update the mirrored values + // + // Read all of the registers in this block and sub-blocks and update their + // mirror values to match their corresponding values in the design. + // The mirroring can be performed using the physical interfaces + // (front-door access) or back-door accesses. + // If the ~check~ argument is specified as , + // an error message is issued if the current mirrored value + // does not match the actual value in the design. + // This method performs the reverse operation of . + // + extern virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // Task -- NODOCS -- write_reg_by_name + // + // Write the named register + // + // Equivalent to followed by + // + extern virtual task write_reg_by_name( + output uvm_status_e status, + input string name, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // Task -- NODOCS -- read_reg_by_name + // + // Read the named register + // + // Equivalent to followed by + // + extern virtual task read_reg_by_name( + output uvm_status_e status, + input string name, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // Task -- NODOCS -- write_mem_by_name + // + // Write the named memory + // + // Equivalent to followed by + // + extern virtual task write_mem_by_name( + output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // Task -- NODOCS -- read_mem_by_name + // + // Read the named memory + // + // Equivalent to followed by + // + extern virtual task read_mem_by_name( + output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + extern virtual task readmemh(string filename); + extern virtual task writememh(string filename); + + + + //---------------- + // Group -- NODOCS -- Backdoor + //---------------- + + // Function -- NODOCS -- get_backdoor + // + // Get the user-defined backdoor for all registers in this block + // + // Return the user-defined backdoor for all register in this + // block and all sub-blocks -- unless overridden by a backdoor set + // in a lower-level block or in the register itself. + // + // If ~inherited~ is TRUE, returns the backdoor of the parent block + // if none have been specified for this block. + // + extern function uvm_reg_backdoor get_backdoor(bit inherited = 1); + + + // Function -- NODOCS -- set_backdoor + // + // Set the user-defined backdoor for all registers in this block + // + // Defines the backdoor mechanism for all registers instantiated + // in this block and sub-blocks, unless overridden by a definition + // in a lower-level block or register. + // + extern function void set_backdoor (uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + + + // Function -- NODOCS -- clear_hdl_path + // + // Delete HDL paths + // + // Remove any previously specified HDL path to the block instance + // for the specified design abstraction. + // + extern function void clear_hdl_path (string kind = "RTL"); + + + // Function -- NODOCS -- add_hdl_path + // + // Add an HDL path + // + // Add the specified HDL path to the block instance for the specified + // design abstraction. This method may be called more than once for the + // same design abstraction if the block is physically duplicated + // in the design abstraction + // + extern function void add_hdl_path (string path, string kind = "RTL"); + + + // Function -- NODOCS -- has_hdl_path + // + // Check if a HDL path is specified + // + // Returns TRUE if the block instance has a HDL path defined for the + // specified design abstraction. If no design abstraction is specified, + // uses the default design abstraction specified for this block or + // the nearest block ancestor with a specified default design abstraction. + // + extern function bit has_hdl_path (string kind = ""); + + + // Function -- NODOCS -- get_hdl_path + // + // Get the incremental HDL path(s) + // + // Returns the HDL path(s) defined for the specified design abstraction + // in the block instance. + // Returns only the component of the HDL paths that corresponds to + // the block, not a full hierarchical path + // + // If no design abstraction is specified, the default design abstraction + // for this block is used. + // + extern function void get_hdl_path (ref string paths[$], input string kind = ""); + + + // Function -- NODOCS -- get_full_hdl_path + // + // Get the full hierarchical HDL path(s) + // + // Returns the full hierarchical HDL path(s) defined for the specified + // design abstraction in the block instance. + // There may be more than one path returned even + // if only one path was defined for the block instance, if any of the + // parent components have more than one path defined for the same design + // abstraction + // + // If no design abstraction is specified, the default design abstraction + // for each ancestor block is used to get each incremental path. + // + extern function void get_full_hdl_path (ref string paths[$], + input string kind = "", + string separator = "."); + + + // Function -- NODOCS -- set_default_hdl_path + // + // Set the default design abstraction + // + // Set the default design abstraction for this block instance. + // + extern function void set_default_hdl_path (string kind); + + + // Function -- NODOCS -- get_default_hdl_path + // + // Get the default design abstraction + // + // Returns the default design abstraction for this block instance. + // If a default design abstraction has not been explicitly set for this + // block instance, returns the default design abstraction for the + // nearest block ancestor. + // Returns "" if no default design abstraction has been specified. + // + extern function string get_default_hdl_path (); + + + // Function -- NODOCS -- set_hdl_path_root + // + // Specify a root HDL path + // + // Set the specified path as the absolute HDL path to the block instance + // for the specified design abstraction. + // This absolute root path is prepended to all hierarchical paths + // under this block. The HDL path of any ancestor block is ignored. + // This method overrides any incremental path for the + // same design abstraction specified using . + // + extern function void set_hdl_path_root (string path, string kind = "RTL"); + + + // Function -- NODOCS -- is_hdl_path_root + // + // Check if this block has an absolute path + // + // Returns TRUE if an absolute HDL path to the block instance + // for the specified design abstraction has been defined. + // If no design abstraction is specified, the default design abstraction + // for this block is used. + // + extern function bit is_hdl_path_root (string kind = ""); + + + extern virtual function void do_print (uvm_printer printer); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + extern virtual function string convert2string (); + extern virtual function uvm_object clone(); + + extern local function void Xinit_address_mapsX(); + + + virtual function void set_lock(bit v); + locked=v; + foreach(blks[idx]) + idx.set_lock(v); + endfunction + + // remove all knowledge of map m and all regs|mems|vregs contained in m from the block + virtual function void unregister(uvm_reg_map m); + foreach(regs[idx]) begin + if(idx.is_in_map(m)) + regs.delete(idx); + end + foreach(mems[idx]) begin + if(idx.is_in_map(m)) + mems.delete(idx); + end + foreach(vregs[idx]) begin + if(idx.is_in_map(m)) + vregs.delete(idx); + end + maps.delete(m); + endfunction +endclass: uvm_reg_block + +//------------------------------------------------------------------------ + + +//--------------- +// Initialization +//--------------- + +// check_data_width + +function bit uvm_reg_block::check_data_width(int unsigned width); + if (width <= $bits(uvm_reg_data_t)) return 1; + + `uvm_fatal("RegModel", $sformatf("Register model requires that UVM_REG_DATA_WIDTH be defined as %0d or greater. Currently defined as %0d", width, `UVM_REG_DATA_WIDTH)) + + return 0; +endfunction + + +// new + +function uvm_reg_block::new(string name="", int has_coverage=UVM_NO_COVERAGE); + super.new(name); + hdl_paths_pool = new("hdl_paths"); + this.has_cover = has_coverage; + // Root block until registered with a parent + m_roots[this] = 0; + if (m_root_names.exists(name)) + m_root_names[name]++; + else + m_root_names[name] = 1; +endfunction: new + + +// configure + +function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path=""); + this.parent = parent; + if (parent != null) + this.parent.add_block(this); + add_hdl_path(hdl_path); +endfunction + + +// add_block + +function void uvm_reg_block::add_block (uvm_reg_block blk); + if (this.is_locked()) begin + `uvm_error("RegModel", "Cannot add subblock to locked block model") + return; + end + if (this.blks.exists(blk)) begin + `uvm_error("RegModel", {"Subblock '",blk.get_name(), + "' has already been registered with block '",get_name(),"'"}) + return; + end + blks[blk] = id++; + if (m_roots.exists(blk)) m_roots.delete(blk); + + begin + string name=blk.get_name(); + if(m_root_names.exists(name)) m_root_names[name]--; + end +endfunction + + +// add_reg + +function void uvm_reg_block::add_reg(uvm_reg rg); + if (this.is_locked()) begin + `uvm_error("RegModel", "Cannot add register to locked block model") + return; + end + + if (this.regs.exists(rg)) begin + `uvm_error("RegModel", {"Register '",rg.get_name(), + "' has already been registered with block '",get_name(),"'"}) + return; + end + + regs[rg] = id++; +endfunction: add_reg + + +// add_vreg + +function void uvm_reg_block::add_vreg(uvm_vreg vreg); + if (this.is_locked()) begin + `uvm_error("RegModel", "Cannot add virtual register to locked block model") + return; + end + + if (this.vregs.exists(vreg)) begin + `uvm_error("RegModel", {"Virtual register '",vreg.get_name(), + "' has already been registered with block '",get_name(),"'"}) + return; + end + vregs[vreg] = id++; +endfunction: add_vreg + + +// add_mem + +function void uvm_reg_block::add_mem(uvm_mem mem); + if (this.is_locked()) begin + `uvm_error("RegModel", "Cannot add memory to locked block model") + return; + end + + if (this.mems.exists(mem)) begin + `uvm_error("RegModel", {"Memory '",mem.get_name(), + "' has already been registered with block '",get_name(),"'"}) + return; + end + mems[mem] = id++; +endfunction: add_mem + + +// set_parent + +function void uvm_reg_block::set_parent(uvm_reg_block parent); + if (this != parent) + this.parent = parent; +endfunction + + +// is_locked + +function bit uvm_reg_block::is_locked(); + return this.locked; +endfunction: is_locked + + +// lock_model + +function void uvm_reg_block::lock_model(); + + if (is_locked()) + return; + + locked = 1; + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.Xlock_modelX(); + end + + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + mem.Xlock_modelX(); + end + + foreach (blks[blk_]) begin + uvm_reg_block blk=blk_; + blk.lock_model(); + end + + if (this.parent == null) begin + int max_size = uvm_reg::get_max_size(); + + if (uvm_reg_field::get_max_size() > max_size) + max_size = uvm_reg_field::get_max_size(); + + if (uvm_mem::get_max_size() > max_size) + max_size = uvm_mem::get_max_size(); + + if (max_size > `UVM_REG_DATA_WIDTH) begin + `uvm_fatal("RegModel", $sformatf("Register model requires that UVM_REG_DATA_WIDTH be defined as %0d or greater. Currently defined as %0d", max_size, `UVM_REG_DATA_WIDTH)) + end + + Xinit_address_mapsX(); + + // Check that root register models have unique names + // NOTE:: https://accellera.mantishub.io/view.php?id=6532 + if(m_root_names[get_name()]>1) + `uvm_error("UVM/REG/DUPLROOT",$sformatf("There are %0d root register models named \"%s\". The names of the root register models have to be unique", + m_root_names[get_name()], get_name())) + + -> m_uvm_lock_model_complete; + end + +endfunction + + + +//-------------------------- +// Get Hierarchical Elements +//-------------------------- + +function string uvm_reg_block::get_full_name(); + if (parent == null) + return get_name(); + + return {parent.get_full_name(), ".", get_name()}; + +endfunction: get_full_name + + +// get_fields + +function void uvm_reg_block::get_fields(ref uvm_reg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.get_fields(fields); + end + + if (hier == UVM_HIER) + foreach (blks[blk_]) + begin + uvm_reg_block blk = blk_; + blk.get_fields(fields); + end + +endfunction: get_fields + + +// get_virtual_fields + +function void uvm_reg_block::get_virtual_fields(ref uvm_vreg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + + foreach (vregs[vreg_]) begin + uvm_vreg vreg = vreg_; + vreg.get_fields(fields); + end + + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_virtual_fields(fields); + end +endfunction: get_virtual_fields + + +// get_registers + +function void uvm_reg_block::get_registers(ref uvm_reg regs[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.regs[rg]) + regs.push_back(rg); + + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_registers(regs); + end +endfunction: get_registers + + +// get_virtual_registers + +function void uvm_reg_block::get_virtual_registers(ref uvm_vreg regs[$], + input uvm_hier_e hier=UVM_HIER); + + foreach (vregs[rg]) + regs.push_back(rg); + + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_virtual_registers(regs); + end +endfunction: get_virtual_registers + + +// get_memories + +function void uvm_reg_block::get_memories(ref uvm_mem mems[$], + input uvm_hier_e hier=UVM_HIER); + + foreach (this.mems[mem_]) begin + uvm_mem mem = mem_; + mems.push_back(mem); + end + + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_memories(mems); + end + +endfunction: get_memories + + +// get_blocks + +function void uvm_reg_block::get_blocks(ref uvm_reg_block blks[$], + input uvm_hier_e hier=UVM_HIER); + + foreach (this.blks[blk_]) begin + uvm_reg_block blk = blk_; + blks.push_back(blk); + if (hier == UVM_HIER) + blk.get_blocks(blks); + end + +endfunction: get_blocks + + +// get_root_blocks + +function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]); + + foreach (m_roots[blk]) begin + blks.push_back(blk); + end + +endfunction + + +// find_blocks +function int uvm_reg_block::find_blocks(input string name, + ref uvm_reg_block blks[$], + input uvm_reg_block root = null, + input uvm_object accessor = null); + uvm_reg_block r[$]; + uvm_reg_block b[$]; + + if (root != null) begin + name = {root.get_full_name(), ".", name}; + b='{root}; + end else begin + get_root_blocks(b); + end + foreach(b[idx]) begin + r.push_back(b[idx]); + b[idx].get_blocks(r); + end + + blks.delete(); + + foreach(r[idx]) begin + if ( uvm_is_match( name, r[idx].get_full_name() ) ) + blks.push_back(r[idx]); + + end + + return blks.size(); +endfunction + + + + +function uvm_reg_block uvm_reg_block::find_block(input string name, + input uvm_reg_block root = null, + input uvm_object accessor = null); + + uvm_reg_block blks[$]; + if (!find_blocks(name, blks, root, accessor)) + return null; + + if (blks.size() > 1) begin + `uvm_warning("MRTH1BLK", + {"More than one block matched the name \"", name, "\"."}) + end + + + return blks[0]; +endfunction + + +// get_maps + +function void uvm_reg_block::get_maps(ref uvm_reg_map maps[$]); + + foreach (this.maps[map]) + maps.push_back(map); + +endfunction + + +// get_parent + +function uvm_reg_block uvm_reg_block::get_parent(); + get_parent = this.parent; +endfunction: get_parent + + +//------------ +// Get-By-Name +//------------ + +// get_block_by_name + +function uvm_reg_block uvm_reg_block::get_block_by_name(string name); + + if (get_name() == name) + return this; + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + + if (blk.get_name() == name) + return blk; + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg_block subblks[$]; + blk_.get_blocks(subblks, UVM_HIER); + + foreach (subblks[j]) + if (subblks[j].get_name() == name) + return subblks[j]; + end + + `uvm_warning("RegModel", {"Unable to locate block '",name, + "' in block '",get_full_name(),"'"}) + return null; + +endfunction: get_block_by_name + + +// get_reg_by_name + +function uvm_reg uvm_reg_block::get_reg_by_name(string name); + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.get_name() == name) + return rg; + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg subregs[$]; + blk_.get_registers(subregs, UVM_HIER); + + foreach (subregs[j]) + if (subregs[j].get_name() == name) + return subregs[j]; + end + + `uvm_warning("RegModel", {"Unable to locate register '",name, + "' in block '",get_full_name(),"'"}) + return null; + +endfunction: get_reg_by_name + + +// get_vreg_by_name + +function uvm_vreg uvm_reg_block::get_vreg_by_name(string name); + + foreach (vregs[rg_]) begin + uvm_vreg rg = rg_; + if (rg.get_name() == name) + return rg; + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_vreg subvregs[$]; + blk_.get_virtual_registers(subvregs, UVM_HIER); + + foreach (subvregs[j]) + if (subvregs[j].get_name() == name) + return subvregs[j]; + end + + `uvm_warning("RegModel", {"Unable to locate virtual register '",name, + "' in block '",get_full_name(),"'"}) + return null; + +endfunction: get_vreg_by_name + + +// get_mem_by_name + +function uvm_mem uvm_reg_block::get_mem_by_name(string name); + + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + if (mem.get_name() == name) + return mem; + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_mem submems[$]; + blk_.get_memories(submems, UVM_HIER); + + foreach (submems[j]) + if (submems[j].get_name() == name) + return submems[j]; + end + + `uvm_warning("RegModel", {"Unable to locate memory '",name, + "' in block '",get_full_name(),"'"}) + return null; + +endfunction: get_mem_by_name + + +// get_field_by_name + +function uvm_reg_field uvm_reg_block::get_field_by_name(string name); + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + uvm_reg_field fields[$]; + + rg.get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg subregs[$]; + blk_.get_registers(subregs, UVM_HIER); + + foreach (subregs[j]) begin + uvm_reg_field fields[$]; + subregs[j].get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + end + + `uvm_warning("RegModel", {"Unable to locate field '",name, + "' in block '",get_full_name(),"'"}) + + return null; + +endfunction: get_field_by_name + + +// get_vfield_by_name + +function uvm_vreg_field uvm_reg_block::get_vfield_by_name(string name); + + foreach (vregs[rg_]) begin + uvm_vreg rg =rg_; + uvm_vreg_field fields[$]; + + rg.get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_vreg subvregs[$]; + blk_.get_virtual_registers(subvregs, UVM_HIER); + + foreach (subvregs[j]) begin + uvm_vreg_field fields[$]; + subvregs[j].get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + end + + `uvm_warning("RegModel", {"Unable to locate virtual field '",name, + "' in block '",get_full_name(),"'"}) + + return null; + +endfunction: get_vfield_by_name + + + +//------------- +// Coverage API +//------------- + +// set_coverage + +function uvm_reg_cvr_t uvm_reg_block::set_coverage(uvm_reg_cvr_t is_on); + this.cover_on = this.has_cover & is_on; + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + void'(rg.set_coverage(is_on)); + end + + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + void'(mem.set_coverage(is_on)); + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + void'(blk.set_coverage(is_on)); + end + + return this.cover_on; +endfunction: set_coverage + + +// sample_values + +function void uvm_reg_block::sample_values(); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.sample_values(); + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.sample_values(); + end +endfunction + + +// XsampleX + +function void uvm_reg_block::XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + sample(addr, is_read, map); + if (parent != null) begin + // ToDo: Call XsampleX in the parent block + // with the offset and map within that block's context + end +endfunction + + +function uvm_reg_cvr_t uvm_reg_block::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage + + +// add_coverage + +function void uvm_reg_block::add_coverage(uvm_reg_cvr_t models); + this.has_cover |= models; +endfunction: add_coverage + + +// has_coverage + +function bit uvm_reg_block::has_coverage(uvm_reg_cvr_t models); + return ((this.has_cover & models) == models); +endfunction: has_coverage + + +// get_coverage + +function bit uvm_reg_block::get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL); + if (this.has_coverage(is_on) == 0) return 0; + return ((this.cover_on & is_on) == is_on); +endfunction: get_coverage + + +//---------------- +// Run-Time Access +//---------------- + + +// reset + +function void uvm_reg_block::reset(string kind = "HARD"); + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.reset(kind); + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.reset(kind); + end +endfunction + + +// needs_update + +function bit uvm_reg_block::needs_update(); + needs_update = 0; + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.needs_update()) + return 1; + end + foreach (blks[blk_]) begin + uvm_reg_block blk =blk_; + if (blk.needs_update()) + return 1; + end +endfunction: needs_update + + +// update + +task uvm_reg_block::update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + + if (!needs_update()) begin + `uvm_info("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating", + fname, lineno, this.get_name()), UVM_HIGH) + return; + end + + `uvm_info("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path", + fname, lineno, this.get_name(), path.name ), UVM_HIGH) + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.needs_update()) begin + rg.update(status, path, null, parent, prior, extension); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + `uvm_error("RegModel", $sformatf("Register \"%s\" could not be updated", + rg.get_full_name())) + return; + end + end + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.update(status,path,parent,prior,extension,fname,lineno); + end +endtask: update + + +// mirror + +task uvm_reg_block::mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_status_e final_status = UVM_IS_OK; + + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.mirror(status, check, path, null, + parent, prior, extension, fname, lineno); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + final_status = status; + end + end + + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + + blk.mirror(status, check, path, parent, prior, extension, fname, lineno); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + final_status = status; + end + end + +endtask: mirror + + +// write_reg_by_name + +task uvm_reg_block::write_reg_by_name(output uvm_status_e status, + input string name, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg rg; + this.fname = fname; + this.lineno = lineno; + + status = UVM_NOT_OK; + rg = this.get_reg_by_name(name); + if (rg != null) + rg.write(status, data, path, map, parent, prior, extension); + +endtask: write_reg_by_name + + +// read_reg_by_name + +task uvm_reg_block::read_reg_by_name(output uvm_status_e status, + input string name, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg rg; + this.fname = fname; + this.lineno = lineno; + + status = UVM_NOT_OK; + rg = this.get_reg_by_name(name); + if (rg != null) + rg.read(status, data, path, map, parent, prior, extension); +endtask: read_reg_by_name + + +// write_mem_by_name + +task uvm_reg_block::write_mem_by_name(output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + + status = UVM_NOT_OK; + mem = get_mem_by_name(name); + if (mem != null) + mem.write(status, offset, data, path, map, parent, prior, extension); +endtask: write_mem_by_name + + +// read_mem_by_name + +task uvm_reg_block::read_mem_by_name(output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + + status = UVM_NOT_OK; + mem = get_mem_by_name(name); + if (mem != null) + mem.read(status, offset, data, path, map, parent, prior, extension); +endtask: read_mem_by_name + + +// readmemh + +task uvm_reg_block::readmemh(string filename); + // TODO +endtask: readmemh + + +// writememh + +task uvm_reg_block::writememh(string filename); + // TODO +endtask: writememh + + +//--------------- +// Map Management +//--------------- + +// create_map + +function uvm_reg_map uvm_reg_block::create_map(string name, + uvm_reg_addr_t base_addr, + int unsigned n_bytes, + uvm_endianness_e endian, + bit byte_addressing=1); + + uvm_reg_map map; + +`ifdef VERILATOR + map = uvm_reg_map::type_id_create(name,,this.get_full_name()); +`else + map = uvm_reg_map::type_id::create(name,,this.get_full_name()); +`endif + map.configure(this,base_addr,n_bytes,endian,byte_addressing); + + add_map(map); + + return map; +endfunction + + +// add_map + +function void uvm_reg_block::add_map(uvm_reg_map map); + + if (this.locked) begin + `uvm_error("RegModel", "Cannot add map to locked model") + return; + end + + if (this.maps.exists(map)) begin + `uvm_error("RegModel", {"Map '",map.get_name(), + "' already exists in '",get_full_name(),"'"}) + return; + end + + this.maps[map] = 1; + if (maps.num() == 1) + default_map = map; + +endfunction: add_map + + +// get_map_by_name + +function uvm_reg_map uvm_reg_block::get_map_by_name(string name); + uvm_reg_map maps[$]; + + this.get_maps(maps); + + foreach (maps[i]) + if (maps[i].get_name() == name) + return maps[i]; + + foreach (maps[i]) begin + uvm_reg_map submaps[$]; + maps[i].get_submaps(submaps, UVM_HIER); + + foreach (submaps[j]) + if (submaps[j].get_name() == name) + return submaps[j]; + end + + + `uvm_warning("RegModel", {"Map with name '",name,"' does not exist in block"}) + return null; +endfunction + + +// set_default_map + +function void uvm_reg_block::set_default_map(uvm_reg_map map); + if (!maps.exists(map)) + `uvm_warning("RegModel", {"Map '",map.get_full_name(),"' does not exist in block"}) + default_map = map; +endfunction + + +// get_default_map + +function uvm_reg_map uvm_reg_block::get_default_map(); + return default_map; +endfunction + +`ifdef UVM_ENABLE_DEPRECATED_API +function uvm_path_e uvm_reg_block::get_default_path(); + return get_default_door(); +endfunction : get_default_path +`endif + +// get_default_door + +function uvm_door_e uvm_reg_block::get_default_door(); + + if (this.default_path != UVM_DEFAULT_DOOR) + return this.default_path; + + if (this.parent != null) + return this.parent.get_default_door(); + + return UVM_FRONTDOOR; + +endfunction + +// set_default_door + +function void uvm_reg_block::set_default_door(uvm_door_e door); + + this.default_path = door; + +endfunction + +// Xinit_address_mapsX + +function void uvm_reg_block::Xinit_address_mapsX(); + foreach (maps[map_]) begin + uvm_reg_map map = map_; + map.Xinit_address_mapX(); + end + //map.Xverify_map_configX(); +endfunction + + +//---------------- +// Group- Backdoor +//---------------- + +// set_backdoor + +function void uvm_reg_block::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + bkdr.fname = fname; + bkdr.lineno = lineno; + if (this.backdoor != null && + this.backdoor.has_update_threads()) begin + `uvm_warning("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.") + end + this.backdoor = bkdr; +endfunction: set_backdoor + + +// get_backdoor + +function uvm_reg_backdoor uvm_reg_block::get_backdoor(bit inherited = 1); + if (backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + while (blk != null) begin + uvm_reg_backdoor bkdr = blk.get_backdoor(); + if (bkdr != null) + return bkdr; + blk = blk.get_parent(); + end + end + return this.backdoor; +endfunction: get_backdoor + + + +// clear_hdl_path + +function void uvm_reg_block::clear_hdl_path(string kind = "RTL"); + + if (kind == "ALL") begin + hdl_paths_pool = new("hdl_paths"); + return; + end + + if (kind == "") + kind = get_default_hdl_path(); + + if (!hdl_paths_pool.exists(kind)) begin + `uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"}) + return; + end + + hdl_paths_pool.delete(kind); +endfunction + + +// add_hdl_path + +function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL"); + + uvm_queue #(string) paths; + + paths = hdl_paths_pool.get(kind); + + paths.push_back(path); + +endfunction + + +// has_hdl_path + +function bit uvm_reg_block::has_hdl_path(string kind = ""); + if (kind == "") begin + kind = get_default_hdl_path(); + end + return hdl_paths_pool.exists(kind); +endfunction + + +// get_hdl_path + +function void uvm_reg_block::get_hdl_path(ref string paths[$], input string kind = ""); + + uvm_queue #(string) hdl_paths; + + if (kind == "") + kind = get_default_hdl_path(); + + if (!has_hdl_path(kind)) begin + `uvm_error("RegModel",{"Block does not have hdl path defined for abstraction '",kind,"'"}) + return; + end + + hdl_paths = hdl_paths_pool.get(kind); + + for (int i=0; i 1) single_map = 0; + end + + if (single_map) begin + $sformat(image, "%sBlock %s", prefix, this.get_full_name()); + + if (map != "") + $sformat(image, "%s.%s", image, map); + + endian = this.get_endian(map); + + $sformat(image, "%s -- %0d bytes (%s)", image, + this.get_n_bytes(map), endian.name()); + + foreach (blks[i]) begin + string img; + img = blks[i].convert2string({prefix, " "}, blk_maps[i]); + image = {image, "\n", img}; + end + + end + else begin + $sformat(image, "%Block %s", prefix, this.get_full_name()); + foreach (maps[i]) begin + string img; + endian = this.get_endian(maps[i]); + $sformat(img, "%s Map \"%s\" -- %0d bytes (%s)", + prefix, maps[i], + this.get_n_bytes(maps[i]), endian.name()); + image = {image, "\n", img}; + + this.get_blocks(blks, blk_maps, maps[i]); + foreach (blks[j]) begin + img = blks[j].convert2string({prefix, " "}, + blk_maps[j]); + image = {image, "\n", img}; + end + + this.get_subsys(sys, blk_maps, maps[i]); + foreach (sys[j]) begin + img = sys[j].convert2string({prefix, " "}, + blk_maps[j]); + image = {image, "\n", img}; + end + end + end +`endif + return image; +endfunction: convert2string diff --git a/test_regress/t/t_uvm/reg/uvm_reg_cbs.svh b/test_regress/t/t_uvm/reg/uvm_reg_cbs.svh new file mode 100644 index 0000000000..b8ed0951c8 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_cbs.svh @@ -0,0 +1,359 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +// ------------------------------------------------------------- +// + +typedef class uvm_reg; +typedef class uvm_mem; +typedef class uvm_reg_backdoor; + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Register Callbacks +// +// This section defines the base class used for all register callback +// extensions. It also includes pre-defined callback extensions for use on +// read-only and write-only registers. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_cbs +// +// Facade class for field, register, memory and backdoor +// access callback methods. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.11.1 +class uvm_reg_cbs extends uvm_callback; + + `uvm_object_utils(uvm_reg_cbs) + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.1 + function new(string name = "uvm_reg_cbs"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.2 + virtual task pre_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.3 + virtual task post_write(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.4 + virtual task pre_read(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.5 + virtual task post_read(uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.6 + virtual function void post_predict(input uvm_reg_field fld, + input uvm_reg_data_t previous, + inout uvm_reg_data_t value, + input uvm_predict_e kind, + input uvm_door_e path, + input uvm_reg_map map); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.7 + virtual function void encode(ref uvm_reg_data_t data[]); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.2.8 + virtual function void decode(ref uvm_reg_data_t data[]); + endfunction + + + +endclass + + +//------------------ +// Section -- NODOCS -- Typedefs +//------------------ + + +// Type -- NODOCS -- uvm_reg_cb +// +// Convenience callback type declaration for registers +// +// Use this declaration to register the register callbacks rather than +// the more verbose parameterized class +// +typedef uvm_callbacks#(uvm_reg, uvm_reg_cbs) uvm_reg_cb /* @uvm-ieee 1800.2-2017 auto D.4.6.1*/ ; + + +// Type -- NODOCS -- uvm_reg_cb_iter +// +// Convenience callback iterator type declaration for registers +// +// Use this declaration to iterate over registered register callbacks +// rather than the more verbose parameterized class +// +typedef uvm_callback_iter#(uvm_reg, uvm_reg_cbs) uvm_reg_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.6.2*/ ; + + +// Type -- NODOCS -- uvm_reg_bd_cb +// +// Convenience callback type declaration for backdoor +// +// Use this declaration to register register backdoor callbacks rather than +// the more verbose parameterized class +// +typedef uvm_callbacks#(uvm_reg_backdoor, uvm_reg_cbs) uvm_reg_bd_cb /* @uvm-ieee 1800.2-2017 auto D.4.6.3*/ ; + + +// Type -- NODOCS -- uvm_reg_bd_cb_iter +// Convenience callback iterator type declaration for backdoor +// +// Use this declaration to iterate over registered register backdoor callbacks +// rather than the more verbose parameterized class +// + +typedef uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) uvm_reg_bd_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.6.4*/ ; + + +// Type -- NODOCS -- uvm_mem_cb +// +// Convenience callback type declaration for memories +// +// Use this declaration to register memory callbacks rather than +// the more verbose parameterized class +// +typedef uvm_callbacks#(uvm_mem, uvm_reg_cbs) uvm_mem_cb /* @uvm-ieee 1800.2-2017 auto D.4.6.5*/ ; + + +// Type -- NODOCS -- uvm_mem_cb_iter +// +// Convenience callback iterator type declaration for memories +// +// Use this declaration to iterate over registered memory callbacks +// rather than the more verbose parameterized class +// +typedef uvm_callback_iter#(uvm_mem, uvm_reg_cbs) uvm_mem_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.6.6*/ ; + + +// Type -- NODOCS -- uvm_reg_field_cb +// +// Convenience callback type declaration for fields +// +// Use this declaration to register field callbacks rather than +// the more verbose parameterized class +// +typedef uvm_callbacks#(uvm_reg_field, uvm_reg_cbs) uvm_reg_field_cb /* @uvm-ieee 1800.2-2017 auto D.4.6.7*/ ; + + +// Type -- NODOCS -- uvm_reg_field_cb_iter +// +// Convenience callback iterator type declaration for fields +// +// Use this declaration to iterate over registered field callbacks +// rather than the more verbose parameterized class +// +typedef uvm_callback_iter#(uvm_reg_field, uvm_reg_cbs) uvm_reg_field_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.6.8*/ ; + + +//----------------------------- +// Group -- NODOCS -- Predefined Extensions +//----------------------------- + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_read_only_cbs +// +// Pre-defined register callback method for read-only registers +// that will issue an error if a write() operation is attempted. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.11.4.1 +class uvm_reg_read_only_cbs extends uvm_reg_cbs; +// SEE MANTIS 6040. This is supposed to be Virtual, but cannot since an instance is +// created. leaving NON virtual for now. + + function new(string name = "uvm_reg_read_only_cbs"); + super.new(name); + endfunction + + `uvm_object_utils(uvm_reg_read_only_cbs) + + + + // @uvm-ieee 1800.2-2017 auto 18.11.4.2.1 + virtual task pre_write(uvm_reg_item rw); + string name = rw.element.get_full_name(); + + if (rw.status != UVM_IS_OK) + return; + + if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field fld; + uvm_reg rg; + $cast(fld, rw.element); + rg = fld.get_parent(); + name = rg.get_full_name(); + end + + `uvm_error("UVM/REG/READONLY", + {name, " is read-only. Cannot call write() method."}) + + rw.status = UVM_NOT_OK; + endtask + + local static uvm_reg_read_only_cbs m_me; + local static function uvm_reg_read_only_cbs get(); + if (m_me == null) m_me = new; + return m_me; + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.4.2.2 + static function void add(uvm_reg rg); + uvm_reg_field flds[$]; + + uvm_reg_cb::add(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::add(flds[i], get()); + end + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.4.2.3 + static function void remove(uvm_reg rg); + uvm_reg_cb_iter cbs = new(rg); + uvm_reg_field flds[$]; + + void'(cbs.first()); + while (cbs.get_cb() != get()) begin + if (cbs.get_cb() == null) + return; + void'(cbs.next()); + end + uvm_reg_cb::delete(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::delete(flds[i], get()); + end + endfunction +endclass + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_reg_write_only_cbs +// +// Pre-defined register callback method for write-only registers +// that will issue an error if a read() operation is attempted. +// +//------------------------------------------------------------------------------ + + +// @uvm-ieee 1800.2-2017 auto 18.11.5.1 +class uvm_reg_write_only_cbs extends uvm_reg_cbs; +// SEE MANTIS 6040. This is supposed to be Virtual, but cannot since an instance is +// created. leaving NON virtual for now. + + // @uvm-ieee 1800.2-2017 auto 18.1.2.1 + function new(string name = "uvm_reg_write_only_cbs"); + super.new(name); + endfunction + + `uvm_object_utils(uvm_reg_write_only_cbs) + + + // @uvm-ieee 1800.2-2017 auto 18.11.5.2.1 + virtual task pre_read(uvm_reg_item rw); + string name = rw.element.get_full_name(); + + if (rw.status != UVM_IS_OK) + return; + + if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field fld; + uvm_reg rg; + $cast(fld, rw.element); + rg = fld.get_parent(); + name = rg.get_full_name(); + end + + `uvm_error("UVM/REG/WRTEONLY", + {name, " is write-only. Cannot call read() method."}) + + rw.status = UVM_NOT_OK; + endtask + + local static uvm_reg_write_only_cbs m_me; + local static function uvm_reg_write_only_cbs get(); + if (m_me == null) m_me = new; + return m_me; + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.5.2.2 + static function void add(uvm_reg rg); + uvm_reg_field flds[$]; + + uvm_reg_cb::add(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::add(flds[i], get()); + end + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.11.5.2.3 + static function void remove(uvm_reg rg); + uvm_reg_cb_iter cbs = new(rg); + uvm_reg_field flds[$]; + + void'(cbs.first()); + while (cbs.get_cb() != get()) begin + if (cbs.get_cb() == null) + return; + void'(cbs.next()); + end + uvm_reg_cb::delete(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::delete(flds[i], get()); + end + endfunction +endclass diff --git a/test_regress/t/t_uvm/reg/uvm_reg_field.svh b/test_regress/t/t_uvm/reg/uvm_reg_field.svh new file mode 100644 index 0000000000..f3d0d0a455 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_field.svh @@ -0,0 +1,1629 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2012-2014 Semifore +// Copyright 2018 Qualcomm, Inc. +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// 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. +// ------------------------------------------------------------- +// + +typedef class uvm_reg_cbs; + + + +// @uvm-ieee 1800.2-2017 auto 18.5.1 +class uvm_reg_field extends uvm_object; + + // Variable -- NODOCS -- value + // Mirrored field value. + // This value can be sampled in a functional coverage model + // or constrained when randomized. + rand uvm_reg_data_t value; // Mirrored after randomize() + + local uvm_reg_data_t m_mirrored; // What we think is in the HW + local uvm_reg_data_t m_desired; // Mirrored after set() + local string m_access; + local uvm_reg m_parent; + local int unsigned m_lsb; + local int unsigned m_size; + local bit m_volatile; + local uvm_reg_data_t m_reset[string]; + local bit m_written; + local bit m_read_in_progress; + local bit m_write_in_progress; + local string m_fname; + local int m_lineno; + local int m_cover_on; + local bit m_individually_accessible; + local uvm_check_e m_check; + + local static int m_max_size; + local static bit m_policy_names[string]; + + constraint uvm_reg_field_valid { + if (`UVM_REG_DATA_WIDTH > m_size) { + value < (`UVM_REG_DATA_WIDTH'h1 << m_size); + } + } + + `uvm_object_utils(uvm_reg_field) + + //---------------------- + // Group -- NODOCS -- Initialization + //---------------------- + + + // @uvm-ieee 1800.2-2017 auto 18.5.3.1 + extern function new(string name = "uvm_reg_field"); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.3.2 + extern function void configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // Function -- NODOCS -- get_name + // + // Get the simple name + // + // Return the simple object name of this field + // + + + // Function -- NODOCS -- get_full_name + // + // Get the hierarchical name + // + // Return the hierarchal name of this field + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.4.1 + extern virtual function uvm_reg get_parent(); + extern virtual function uvm_reg get_register(); + + + // Function -- NODOCS -- get_lsb_pos + // + // Return the position of the field + // + // Returns the index of the least significant bit of the field + // in the register that instantiates it. + // An offset of 0 indicates a field that is aligned with the + // least-significant bit of the register. + // + extern virtual function int unsigned get_lsb_pos(); + + + // Function -- NODOCS -- get_n_bits + // + // Returns the width, in number of bits, of the field. + // + extern virtual function int unsigned get_n_bits(); + + // + // FUNCTION -- NODOCS -- get_max_size + // Returns the width, in number of bits, of the largest field. + // + extern static function int unsigned get_max_size(); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.4.6 + extern virtual function string set_access(string mode); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.4.7 + extern static function bit define_access(string name); + local static bit m_predefined = m_predefine_policies(); + extern local static function bit m_predefine_policies(); + + // Function -- NODOCS -- get_access + // + // Get the access policy of the field + // + // Returns the current access policy of the field + // when written and read through the specified address ~map~. + // If the register containing the field is mapped in multiple + // address map, an address map must be specified. + // The access policy of a field from a specific + // address map may be restricted by the register's access policy in that + // address map. + // For example, a RW field may only be writable through one of + // the address maps and read-only through all of the other maps. + // If the field access contradicts the map's access value + // (field access of WO, and map access value of RO, etc), the + // method's return value is NOACCESS. + + // @uvm-ieee 1800.2-2017 auto 18.5.4.5 + extern virtual function string get_access(uvm_reg_map map = null); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.4.8 + extern virtual function bit is_known_access(uvm_reg_map map = null); + + + // @uvm-ieee 1800.2-2017 auto 18.5.4.9 + extern virtual function void set_volatility(bit volatile); + + + // @uvm-ieee 1800.2-2017 auto 18.5.4.10 + extern virtual function bit is_volatile(); + + + //-------------- + // Group -- NODOCS -- Access + //-------------- + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.2 + extern virtual function void set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.1 + extern virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.3 + extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "", + int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.4 + extern virtual function void reset(string kind = "HARD"); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.6 + extern virtual function uvm_reg_data_t get_reset(string kind = "HARD"); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.5 + extern virtual function bit has_reset(string kind = "HARD", + bit delete = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.7 + extern virtual function void set_reset(uvm_reg_data_t value, + string kind = "HARD"); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.8 + extern virtual function bit needs_update(); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.9 + extern virtual task write (output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.10 + extern virtual task read (output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.11 + extern virtual task poke (output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.12 + extern virtual task peek (output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.13 + extern virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.15 + extern function void set_compare(uvm_check_e check=UVM_CHECK); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.14 + extern function uvm_check_e get_compare(); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.16 + extern function bit is_indv_accessible (uvm_door_e path, + uvm_reg_map local_map); + + + + // @uvm-ieee 1800.2-2017 auto 18.5.5.17 + extern function bit predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + + + + /*local*/ + extern virtual function uvm_reg_data_t XpredictX (uvm_reg_data_t cur_val, + uvm_reg_data_t wr_val, + uvm_reg_map map); + + /*local*/ + extern virtual function uvm_reg_data_t XupdateX(); + + /*local*/ + extern function bit Xcheck_accessX (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + + extern virtual task do_write(uvm_reg_item rw); + extern virtual task do_read(uvm_reg_item rw); + extern virtual function void do_predict + (uvm_reg_item rw, + uvm_predict_e kind=UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + + + extern function void pre_randomize(); + extern function void post_randomize(); + + + //----------------- + // Group -- NODOCS -- Callbacks + //----------------- + + `uvm_register_cb(uvm_reg_field, uvm_reg_cbs) + + + + // @uvm-ieee 1800.2-2017 auto 18.5.6.1 + virtual task pre_write (uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.5.6.2 + virtual task post_write (uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.5.6.3 + virtual task pre_read (uvm_reg_item rw); endtask + + + + // @uvm-ieee 1800.2-2017 auto 18.5.6.4 + virtual task post_read (uvm_reg_item rw); endtask + + + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + +endclass: uvm_reg_field + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// new + +function uvm_reg_field::new(string name = "uvm_reg_field"); + super.new(name); +endfunction: new + + +// configure + +function void uvm_reg_field::configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + m_parent = parent; + if (size == 0) begin + `uvm_error("RegModel", + $sformatf("Field \"%s\" cannot have 0 bits", get_full_name())) + size = 1; + end + + m_size = size; + m_volatile = volatile; + m_access = access.toupper(); + m_lsb = lsb_pos; + m_cover_on = UVM_NO_COVERAGE; + m_written = 0; + m_check = volatile ? UVM_NO_CHECK : UVM_CHECK; + m_individually_accessible = individually_accessible; + + if (has_reset) + set_reset(reset); + + m_parent.add_field(this); + + if (!m_policy_names.exists(m_access)) begin + `uvm_error("RegModel", {"Access policy '",access, + "' for field '",get_full_name(),"' is not defined. Setting to RW"}) + m_access = "RW"; + end + + if (size > m_max_size) + m_max_size = size; + + // Ignore is_rand if the field is known not to be writeable + // i.e. not "RW", "WRC", "WRS", "WO", "W1", "WO1" + case (access) + "RO", "RC", "RS", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", + "WOC", "WOS": is_rand = 0; + endcase + + if (!is_rand) + value.rand_mode(0); + +endfunction: configure + + +// get_parent + +function uvm_reg uvm_reg_field::get_parent(); + return m_parent; +endfunction: get_parent + + +// get_full_name + +function string uvm_reg_field::get_full_name(); + return {m_parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name + + +// get_register + +function uvm_reg uvm_reg_field::get_register(); + return m_parent; +endfunction: get_register + + +// get_lsb_pos + +function int unsigned uvm_reg_field::get_lsb_pos(); + return m_lsb; +endfunction: get_lsb_pos + + +// get_n_bits + +function int unsigned uvm_reg_field::get_n_bits(); + return m_size; +endfunction: get_n_bits + + +// get_max_size + +function int unsigned uvm_reg_field::get_max_size(); + return m_max_size; +endfunction: get_max_size + + +// is_known_access + +function bit uvm_reg_field::is_known_access(uvm_reg_map map = null); + string acc = get_access(map); + case (acc) + "RO", "RW", "RC", "RS", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "WRC", "WRS", "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", + "WO", "WOC", "WOS", "W1", "WO1" : return 1; + endcase + return 0; +endfunction + + +// get_access + +function string uvm_reg_field::get_access(uvm_reg_map map = null); + string field_access = m_access; + + if (map == uvm_reg_map::backdoor()) + return field_access; + + // Is the register restricted in this map? + case (m_parent.get_rights(map)) + "RW": + // No restrictions + return field_access; + + "RO": + case (field_access) + "RW", "RO", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "W1" + : field_access = "RO"; + + "RC", "WRC", "W1SRC", "W0SRC", "WSRC" + : field_access = "RC"; + + "RS", "WRS", "W1CRS", "W0CRS", "WCRS" + : field_access = "RS"; + + "WO", "WOC", "WOS", "WO1": begin + field_access = "NOACCESS"; + end + + // No change for the other modes + endcase + + "WO": + case (field_access) + "RW","WRC","WRS" : field_access = "WO"; + "W1SRC" : field_access = "W1S"; + "W0SRC": field_access = "W0S"; + "W1CRS": field_access = "W1C"; + "W0CRS": field_access = "W0C"; + "WCRS": field_access = "WC"; + "W1" : field_access = "W1"; + "WO1" : field_access = "WO1"; + "WSRC" : field_access = "WS"; + "RO","RC","RS": field_access = "NOACCESS"; + // No change for the other modes + // "WO","WC","WS","W1C","W1S","W0C","W0S","W0T","W1" : null; + + endcase + + default: + begin + field_access = "NOACCESS"; + `uvm_warning("RegModel", {"Register '",m_parent.get_full_name(), + "' containing field '",get_name(),"' is mapped in map '", + map.get_full_name(),"' with unknown access right '", m_parent.get_rights(map), "'"}) + end + endcase + return field_access; +endfunction: get_access + + +// set_access + +function string uvm_reg_field::set_access(string mode); + set_access = m_access; + m_access = mode.toupper(); + if (!m_policy_names.exists(m_access)) begin + `uvm_error("RegModel", {"Access policy '",m_access, + "' is not a defined field access policy"}) + m_access = set_access; + end +endfunction: set_access + + +// define_access + +function bit uvm_reg_field::define_access(string name); + if (!m_predefined) m_predefined = m_predefine_policies(); + + name = name.toupper(); + + if (m_policy_names.exists(name)) return 0; + + m_policy_names[name] = 1; + return 1; +endfunction + + +// m_predefined_policies + +function bit uvm_reg_field::m_predefine_policies(); + if (m_predefined) return 1; + + m_predefined = 1; + + void'(define_access("RO")); + void'(define_access("RW")); + void'(define_access("RC")); + void'(define_access("RS")); + void'(define_access("WRC")); + void'(define_access("WRS")); + void'(define_access("WC")); + void'(define_access("WS")); + void'(define_access("WSRC")); + void'(define_access("WCRS")); + void'(define_access("W1C")); + void'(define_access("W1S")); + void'(define_access("W1T")); + void'(define_access("W0C")); + void'(define_access("W0S")); + void'(define_access("W0T")); + void'(define_access("W1SRC")); + void'(define_access("W1CRS")); + void'(define_access("W0SRC")); + void'(define_access("W0CRS")); + void'(define_access("WO")); + void'(define_access("WOC")); + void'(define_access("WOS")); + void'(define_access("W1")); + void'(define_access("WO1")); + return 1; +endfunction + + +// set_volatility + +function void uvm_reg_field::set_volatility(bit volatile); + m_volatile = volatile; +endfunction + + +// is_volatile + +function bit uvm_reg_field::is_volatile(); + return m_volatile; +endfunction + + +// XpredictX + +function uvm_reg_data_t uvm_reg_field::XpredictX (uvm_reg_data_t cur_val, + uvm_reg_data_t wr_val, + uvm_reg_map map); + uvm_reg_data_t mask = ('b1 << m_size)-1; + + case (get_access(map)) + "RO": return cur_val; + "RW": return wr_val; + "RC": return cur_val; + "RS": return cur_val; + "WC": return '0; + "WS": return mask; + "WRC": return wr_val; + "WRS": return wr_val; + "WSRC": return mask; + "WCRS": return '0; + "W1C": return cur_val & (~wr_val); + "W1S": return cur_val | wr_val; + "W1T": return cur_val ^ wr_val; + "W0C": return cur_val & wr_val; + "W0S": return cur_val | (~wr_val & mask); + "W0T": return cur_val ^ (~wr_val & mask); + "W1SRC": return cur_val | wr_val; + "W1CRS": return cur_val & (~wr_val); + "W0SRC": return cur_val | (~wr_val & mask); + "W0CRS": return cur_val & wr_val; + "WO": return wr_val; + "WOC": return '0; + "WOS": return mask; + "W1": return (m_written) ? cur_val : wr_val; + "WO1": return (m_written) ? cur_val : wr_val; + "NOACCESS": return cur_val; + default: return wr_val; + endcase + + `uvm_fatal("RegModel", "uvm_reg_field::XpredictX(): Internal error") + return 0; +endfunction: XpredictX + + + +// predict + +function bit uvm_reg_field::predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_item rw = new; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.fname = fname; + rw.lineno = lineno; + do_predict(rw, kind, be); + predict = (rw.status == UVM_NOT_OK) ? 0 : 1; +endfunction: predict + + +// do_predict + +function void uvm_reg_field::do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + + uvm_reg_data_t field_val = rw.value[0] & ((1 << m_size)-1); + + if (rw.status != UVM_NOT_OK) + rw.status = UVM_IS_OK; + + // Assume that the entire field is enabled + if (!be[0]) + return; + + m_fname = rw.fname; + m_lineno = rw.lineno; + + case (kind) + + UVM_PREDICT_WRITE: + begin + uvm_reg_field_cb_iter cbs = new(this); + + if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) + field_val = XpredictX(m_mirrored, field_val, rw.map); + + m_written = 1; + + for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) + cb.post_predict(this, m_mirrored, field_val, + UVM_PREDICT_WRITE, rw.path, rw.map); + + field_val &= ('b1 << m_size)-1; + + end + + UVM_PREDICT_READ: + begin + uvm_reg_field_cb_iter cbs = new(this); + + if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) begin + + string acc = get_access(rw.map); + + if (acc == "RC" || + acc == "WRC" || + acc == "WSRC" || + acc == "W1SRC" || + acc == "W0SRC") + field_val = 0; // (clear) + + else if (acc == "RS" || + acc == "WRS" || + acc == "WCRS" || + acc == "W1CRS" || + acc == "W0CRS") + field_val = ('b1 << m_size)-1; // all 1's (set) + + else if (acc == "WO" || + acc == "WOC" || + acc == "WOS" || + acc == "WO1" || + acc == "NOACCESS") + return; + end + + for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) + cb.post_predict(this, m_mirrored, field_val, + UVM_PREDICT_READ, rw.path, rw.map); + + field_val &= ('b1 << m_size)-1; + + end + + UVM_PREDICT_DIRECT: + begin + if (m_parent.is_busy()) begin + `uvm_warning("RegModel", {"Trying to predict value of field '", + get_name(),"' while register '",m_parent.get_full_name(), + "' is being accessed"}) + rw.status = UVM_NOT_OK; + end + end + endcase + + // update the mirror with predicted value + m_mirrored = field_val; + m_desired = field_val; + this.value = field_val; + +endfunction: do_predict + + +// XupdateX + +function uvm_reg_data_t uvm_reg_field::XupdateX(); + // Figure out which value must be written to get the desired value + // given what we think is the current value in the hardware + XupdateX = 0; + + case (m_access) + "RO": XupdateX = m_desired; + "RW": XupdateX = m_desired; + "RC": XupdateX = m_desired; + "RS": XupdateX = m_desired; + "WRC": XupdateX = m_desired; + "WRS": XupdateX = m_desired; + "WC": XupdateX = m_desired; // Warn if != 0 + "WS": XupdateX = m_desired; // Warn if != 1 + "WSRC": XupdateX = m_desired; // Warn if != 1 + "WCRS": XupdateX = m_desired; // Warn if != 0 + "W1C": XupdateX = ~m_desired; + "W1S": XupdateX = m_desired; + "W1T": XupdateX = m_desired ^ m_mirrored; + "W0C": XupdateX = m_desired; + "W0S": XupdateX = ~m_desired; + "W0T": XupdateX = ~(m_desired ^ m_mirrored); + "W1SRC": XupdateX = m_desired; + "W1CRS": XupdateX = ~m_desired; + "W0SRC": XupdateX = ~m_desired; + "W0CRS": XupdateX = m_desired; + "WO": XupdateX = m_desired; + "WOC": XupdateX = m_desired; // Warn if != 0 + "WOS": XupdateX = m_desired; // Warn if != 1 + "W1": XupdateX = m_desired; + "WO1": XupdateX = m_desired; + default: XupdateX = m_desired; + endcase + XupdateX &= (1 << m_size) - 1; + +endfunction: XupdateX + + +// set + +function void uvm_reg_field::set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + uvm_reg_data_t mask = ('b1 << m_size)-1; + + m_fname = fname; + m_lineno = lineno; + if (value >> m_size) begin + `uvm_warning("RegModel", + $sformatf("Specified value (0x%h) greater than field \"%s\" size (%0d bits)", + value, get_name(), m_size)) + value &= mask; + end + + if (m_parent.is_busy()) begin + `uvm_warning("UVM/FLD/SET/BSY", + $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.", + get_name(), m_parent.get_full_name())) + end + + case (m_access) + "RO": m_desired = m_desired; + "RW": m_desired = value; + "RC": m_desired = m_desired; + "RS": m_desired = m_desired; + "WC": m_desired = '0; + "WS": m_desired = mask; + "WRC": m_desired = value; + "WRS": m_desired = value; + "WSRC": m_desired = mask; + "WCRS": m_desired = '0; + "W1C": m_desired = m_desired & (~value); + "W1S": m_desired = m_desired | value; + "W1T": m_desired = m_desired ^ value; + "W0C": m_desired = m_desired & value; + "W0S": m_desired = m_desired | (~value & mask); + "W0T": m_desired = m_desired ^ (~value & mask); + "W1SRC": m_desired = m_desired | value; + "W1CRS": m_desired = m_desired & (~value); + "W0SRC": m_desired = m_desired | (~value & mask); + "W0CRS": m_desired = m_desired & value; + "WO": m_desired = value; + "WOC": m_desired = '0; + "WOS": m_desired = mask; + "W1": m_desired = (m_written) ? m_desired : value; + "WO1": m_desired = (m_written) ? m_desired : value; + default: m_desired = value; + endcase + this.value = m_desired; +endfunction: set + + +// get + +function uvm_reg_data_t uvm_reg_field::get(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get = m_desired; +endfunction: get + + +// get_mirrored_value + +function uvm_reg_data_t uvm_reg_field::get_mirrored_value(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get_mirrored_value = m_mirrored; +endfunction: get_mirrored_value + + +// reset + +function void uvm_reg_field::reset(string kind = "HARD"); + + if (!m_reset.exists(kind)) + return; + + m_mirrored = m_reset[kind]; + m_desired = m_mirrored; + value = m_mirrored; + + if (kind == "HARD") + m_written = 0; + +endfunction: reset + + +// has_reset + +function bit uvm_reg_field::has_reset(string kind = "HARD", + bit delete = 0); + + if (!m_reset.exists(kind)) return 0; + + if (delete) m_reset.delete(kind); + + return 1; +endfunction: has_reset + + +// get_reset + +function uvm_reg_data_t + uvm_reg_field::get_reset(string kind = "HARD"); + + if (!m_reset.exists(kind)) + return m_desired; + + return m_reset[kind]; + +endfunction: get_reset + + +// set_reset + +function void uvm_reg_field::set_reset(uvm_reg_data_t value, + string kind = "HARD"); + m_reset[kind] = value & ((1<> m_size) begin + `uvm_warning("RegModel", {"uvm_reg_field::write(): Value greater than field '", + get_full_name(),"'"}) + rw.value[0] &= ((1<> m_lsb) & ((1<> m_lsb) & ((1<0) begin + prev_lsb = fields[fld_idx-1].get_lsb_pos(); + prev_sz = fields[fld_idx-1].get_n_bits(); + end + + if (fld_idx < fields.size()-1) begin + next_lsb = fields[fld_idx+1].get_lsb_pos(); + next_sz = fields[fld_idx+1].get_n_bits(); + end + + // if first field in register + if (fld_idx == 0 && + ((next_lsb % bus_sz) == 0 || + (next_lsb - this_sz) > (next_lsb % bus_sz))) + return 1; + + // if last field in register + else if (fld_idx == (fields.size()-1) && + ((this_lsb % bus_sz) == 0 || + (this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz))) + return 1; + + // if somewhere in between + else begin + if ((this_lsb % bus_sz) == 0) begin + if ((next_lsb % bus_sz) == 0 || + (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz)) + return 1; + end + else begin + if ( (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz) && + ((this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz)) ) + return 1; + end + end + end + end + + `uvm_warning("RegModel", + {"Target bus does not support byte enabling, and the field '", + get_full_name(),"' is not the only field within the entire bus width. ", + "Individual field access will not be available. ", + "Accessing complete register instead."}) + + return 0; + +endfunction + + +// poke + +task uvm_reg_field::poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + + m_fname = fname; + m_lineno = lineno; + + if (value >> m_size) begin + `uvm_warning("RegModel", + {"uvm_reg_field::poke(): Value exceeds size of field '", + get_name(),"'"}) + value &= value & ((1<> m_lsb) & ((1< subtype. + // + virtual function void build(); +`ifdef VERILATOR + value = uvm_reg_field::type_id_create("value"); +`else + value = uvm_reg_field::type_id::create("value"); +`endif + value.configure(this, get_n_bits(), 0, "RW", 0, 32'h0, 1, 0, 1); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.8.3.2 + function void set_compare(uvm_check_e check=UVM_CHECK); + value.set_compare(check); + endfunction + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // Function -- NODOCS -- size + // + // The number of entries currently in the FIFO. + // + function int unsigned size(); + return fifo.size(); + endfunction + + + // Function -- NODOCS -- capacity + // + // The maximum number of entries, or depth, of the FIFO. + + function int unsigned capacity(); + return m_size; + endfunction + + + //-------------- + // Group -- NODOCS -- Access + //-------------- + + // Function -- NODOCS -- write + // + // Pushes the given value to the DUT FIFO. If auto-prediction is enabled, + // the written value is also pushed to the abstract FIFO before the + // call returns. If auto-prediction is not enabled (via + // ), the value is pushed to abstract + // FIFO only when the write operation is observed on the target bus. + // This mode requires using the class. + // If the write is via an operation, the abstract FIFO + // already contains the written value and is thus not affected by + // either prediction mode. + + + // Function -- NODOCS -- read + // + // Reads the next value out of the DUT FIFO. If auto-prediction is + // enabled, the frontmost value in abstract FIFO is popped. + + + + // @uvm-ieee 1800.2-2017 auto 18.8.5.2 + virtual function void set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + // emulate write, with intention of update + value &= ((1 << get_n_bits())-1); + if (fifo.size() == m_size) begin + return; + end + super.set(value,fname,lineno); + m_set_cnt++; + fifo.push_back(this.value.value); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.8.5.7 + virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t upd; + if (!m_set_cnt || fifo.size() == 0) + return; + m_update_in_progress = 1; + for (int i=fifo.size()-m_set_cnt; m_set_cnt > 0; i++, m_set_cnt--) begin + if (i >= 0) begin + //uvm_reg_data_t val = get(); + //super.update(status,path,map,parent,prior,extension,fname,lineno); + write(status,fifo[i],path,map,parent,prior,extension,fname,lineno); + end + end + m_update_in_progress = 0; + endtask + + + // Function -- NODOCS -- mirror + // + // Reads the next value out of the DUT FIFO. If auto-prediction is + // enabled, the frontmost value in abstract FIFO is popped. If + // the ~check~ argument is set and comparison is enabled with + // . + + + + // @uvm-ieee 1800.2-2017 auto 18.8.5.1 + virtual function uvm_reg_data_t get(string fname="", int lineno=0); + //return fifo.pop_front(); + return fifo[0]; + endfunction + + + // Function -- NODOCS -- do_predict + // + // Updates the abstract (mirror) FIFO based on and + // operations. When auto-prediction is on, this method + // is called before each read, write, peek, or poke operation returns. + // When auto-prediction is off, this method is called by a + // upon receipt and conversion of an observed bus + // operation to this register. + // + // If a write prediction, the observed + // write value is pushed to the abstract FIFO as long as it is + // not full and the operation did not originate from an . + // If a read prediction, the observed read value is compared + // with the frontmost value in the abstract FIFO if + // enabled comparison and the FIFO is not empty. + // + virtual function void do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + + super.do_predict(rw,kind,be); + + if (rw.status == UVM_NOT_OK) + return; + + case (kind) + + UVM_PREDICT_WRITE, + UVM_PREDICT_DIRECT: + begin + if (fifo.size() != m_size && !m_update_in_progress) + fifo.push_back(this.value.value); + end + + UVM_PREDICT_READ: + begin + uvm_reg_data_t value = rw.value[0] & ((1 << get_n_bits())-1); + uvm_reg_data_t mirror_val; + if (fifo.size() == 0) begin + return; + end + mirror_val = fifo.pop_front(); + if (this.value.get_compare() == UVM_CHECK && mirror_val != value) begin + `uvm_warning("MIRROR_MISMATCH", + $sformatf("Observed DUT read value 'h%0h != mirror value 'h%0h",value,mirror_val)) + end + end + + endcase + + endfunction + + + // Group -- NODOCS -- Special Overrides + + // Task -- NODOCS -- pre_write + // + // Special pre-processing for a or . + // Called as a result of a or . It is an error to + // attempt a write to a full FIFO or a write while an update is still + // pending. An update is pending after one or more calls to . + // If in your application the DUT allows writes to a full FIFO, you + // must override ~pre_write~ as appropriate. + // + virtual task pre_write(uvm_reg_item rw); + if (m_set_cnt && !m_update_in_progress) begin + `uvm_error("Needs Update","Must call update() after set() and before write()") + rw.status = UVM_NOT_OK; + return; + end + if (fifo.size() >= m_size && !m_update_in_progress) begin + `uvm_error("FIFO Full","Write to full FIFO ignored") + rw.status = UVM_NOT_OK; + return; + end + endtask + + + // Task -- NODOCS -- pre_read + // + // Special post-processing for a or . + // Aborts the operation if the internal FIFO is empty. If in your application + // the DUT does not behave this way, you must override ~pre_write~ as + // appropriate. + // + // + virtual task pre_read(uvm_reg_item rw); + // abort if fifo empty + if (fifo.size() == 0) begin + rw.status = UVM_NOT_OK; + return; + end + endtask + + + function void post_randomize(); + m_set_cnt = 0; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/reg/uvm_reg_file.svh b/test_regress/t/t_uvm/reg/uvm_reg_file.svh new file mode 100644 index 0000000000..2ece425016 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_file.svh @@ -0,0 +1,408 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2015 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. +// ------------------------------------------------------------- +// + + + +// @uvm-ieee 1800.2-2017 auto 18.3.1 +class uvm_reg_file extends uvm_object; + + local uvm_reg_block parent; + local uvm_reg_file m_rf; + local string default_hdl_path = "RTL"; + local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; + + + `uvm_object_utils(uvm_reg_file) + + + //---------------------- + // Group -- NODOCS -- Initialization + //---------------------- + + + // @uvm-ieee 1800.2-2017 auto 18.3.2.1 + extern function new (string name=""); + + + // @uvm-ieee 1800.2-2017 auto 18.3.2.2 + extern function void configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent, + string hdl_path = ""); + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // + // Function -- NODOCS -- get_name + // Get the simple name + // + // Return the simple object name of this register file. + // + + // + // Function -- NODOCS -- get_full_name + // Get the hierarchical name + // + // Return the hierarchal name of this register file. + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + // @uvm-ieee 1800.2-2017 auto 18.3.3.1 + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + + + // @uvm-ieee 1800.2-2017 auto 18.3.3.2 + extern virtual function uvm_reg_file get_regfile (); + + + //---------------- + // Group -- NODOCS -- Backdoor + //---------------- + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.1 + extern function void clear_hdl_path (string kind = "RTL"); + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.2 + extern function void add_hdl_path (string path, string kind = "RTL"); + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.3 + extern function bit has_hdl_path (string kind = ""); + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.4 + extern function void get_hdl_path (ref string paths[$], input string kind = ""); + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.5 + extern function void get_full_hdl_path (ref string paths[$], + input string kind = "", + input string separator = "."); + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.7 + extern function void set_default_hdl_path (string kind); + + + // @uvm-ieee 1800.2-2017 auto 18.3.4.6 + extern function string get_default_hdl_path (); + + + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone (); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + +endclass: uvm_reg_file + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// new + +function uvm_reg_file::new(string name=""); + super.new(name); + hdl_paths_pool = new("hdl_paths"); +endfunction: new + + +// configure + +function void uvm_reg_file::configure(uvm_reg_block blk_parent, uvm_reg_file regfile_parent, string hdl_path = ""); + if (blk_parent == null) begin + `uvm_error("UVM/RFILE/CFG/NOBLK", {"uvm_reg_file::configure() called without a parent block for instance \"", get_name(), "\" of register file type \"", get_type_name(), "\"."}) + return; + end + + this.parent = blk_parent; + this.m_rf = regfile_parent; + this.add_hdl_path(hdl_path); +endfunction: configure + + +// get_block + +function uvm_reg_block uvm_reg_file::get_block(); + get_block = this.parent; +endfunction: get_block + + +// get_regfile + +function uvm_reg_file uvm_reg_file::get_regfile(); + return m_rf; +endfunction + + +// clear_hdl_path + +function void uvm_reg_file::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + hdl_paths_pool = new("hdl_paths"); + return; + end + + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + + if (!hdl_paths_pool.exists(kind)) begin + `uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"}) + return; + end + + hdl_paths_pool.delete(kind); +endfunction + + +// add_hdl_path + +function void uvm_reg_file::add_hdl_path(string path, string kind = "RTL"); + + uvm_queue #(string) paths; + + paths = hdl_paths_pool.get(kind); + + paths.push_back(path); + +endfunction + + +// has_hdl_path + +function bit uvm_reg_file::has_hdl_path(string kind = ""); + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + + return hdl_paths_pool.exists(kind); +endfunction + + +// get_hdl_path + +function void uvm_reg_file::get_hdl_path(ref string paths[$], input string kind = ""); + + uvm_queue #(string) hdl_paths; + + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + + if (!has_hdl_path(kind)) begin + `uvm_error("RegModel",{"Register does not have hdl path defined for abstraction '",kind,"'"}) + return; + end + + hdl_paths = hdl_paths_pool.get(kind); + + for (int i=0; i= m_tbl.size()) begin + `uvm_error(get_full_name(), $sformatf("Address register %s has a value (%0d) greater than the maximum indirect register array size (%0d)", m_idx.get_full_name(), m_idx.get(), m_tbl.size())) + rw.status = UVM_NOT_OK; + return; + end + + //NOTE limit to 2**32 registers + begin + int unsigned idx = m_idx.get(); + m_tbl[idx].do_predict(rw, kind, be); + end + endfunction + + + virtual function uvm_reg_map get_local_map(uvm_reg_map map); + return m_idx.get_local_map(map); + endfunction + + // + // Just for good measure, to catch and short-circuit non-sensical uses + // + virtual function void add_field (uvm_reg_field field); + `uvm_error(get_full_name(), "Cannot add field to an indirect data access register") + endfunction + + virtual function void set (uvm_reg_data_t value, + string fname = "", + int lineno = 0); + `uvm_error(get_full_name(), "Cannot set() an indirect data access register") + endfunction + + virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + `uvm_error(get_full_name(), "Cannot get() an indirect data access register") + return 0; + endfunction + + virtual function uvm_reg get_indirect_reg(string fname = "", + int lineno = 0); + int unsigned idx = m_idx.get_mirrored_value(); + return(m_tbl[idx]); + endfunction + + virtual function bit needs_update(); + return 0; + endfunction + + virtual task write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = get_parent(); + path = blk.get_default_door(); + end + + if (path == UVM_BACKDOOR) begin + `uvm_warning(get_full_name(), "Cannot backdoor-write an indirect data access register. Switching to frontdoor.") + path = UVM_FRONTDOOR; + end + + // Can't simply call super.write() because it'll call set() + begin + uvm_reg_item rw; + + XatomicX(1); + +`ifdef VERILATOR + rw = uvm_reg_item::type_id_create("write_item",,get_full_name()); +`else + rw = uvm_reg_item::type_id::create("write_item",,get_full_name()); +`endif + rw.element = this; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + + do_write(rw); + + status = rw.status; + + XatomicX(0); + end + endtask + + virtual task read(output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = get_parent(); + path = blk.get_default_door(); + end + + if (path == UVM_BACKDOOR) begin + `uvm_warning(get_full_name(), "Cannot backdoor-read an indirect data access register. Switching to frontdoor.") + path = UVM_FRONTDOOR; + end + + super.read(status, value, path, map, parent, prior, extension, fname, lineno); + endtask + + virtual task poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + `uvm_error(get_full_name(), "Cannot poke() an indirect data access register") + status = UVM_NOT_OK; + endtask + + virtual task peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + `uvm_error(get_full_name(), "Cannot peek() an indirect data access register") + status = UVM_NOT_OK; + endtask + + virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + endtask + + virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + endtask + +endclass : uvm_reg_indirect_data + + +class uvm_reg_indirect_ftdr_seq extends uvm_reg_frontdoor; + local uvm_reg m_addr_reg; + local uvm_reg m_data_reg; + local int m_idx; + + function new(uvm_reg addr_reg, + int idx, + uvm_reg data_reg); + super.new("uvm_reg_indirect_ftdr_seq"); + m_addr_reg = addr_reg; + m_idx = idx; + m_data_reg = data_reg; + endfunction: new + + virtual task body(); + + uvm_reg_item rw; + + $cast(rw,rw_info.clone()); + rw.element = m_addr_reg; + rw.kind = UVM_WRITE; + rw.value[0]= m_idx; + + m_addr_reg.XatomicX(1); + m_data_reg.XatomicX(1); + + m_addr_reg.do_write(rw); + + if (rw.status == UVM_NOT_OK) + return; + + $cast(rw,rw_info.clone()); + rw.element = m_data_reg; + + if (rw_info.kind == UVM_WRITE) + m_data_reg.do_write(rw); + else begin + m_data_reg.do_read(rw); + rw_info.value[0] = rw.value[0]; + end + + m_addr_reg.XatomicX(0); + m_data_reg.XatomicX(0); + + rw_info.status = rw.status; + endtask + +endclass diff --git a/test_regress/t/t_uvm/reg/uvm_reg_item.svh b/test_regress/t/t_uvm/reg/uvm_reg_item.svh new file mode 100644 index 0000000000..ebfdfbd910 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_item.svh @@ -0,0 +1,276 @@ +// +//-------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +//-------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Generic Register Operation Descriptors +// +// This section defines the abstract register transaction item. It also defines +// a descriptor for a physical bus operation that is used by +// subtypes to convert from a protocol-specific address/data/rw operation to +// a bus-independent, canonical r/w operation. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// CLASS -- NODOCS -- uvm_reg_item +// +// Defines an abstract register transaction item. No bus-specific information +// is present, although a handle to a is provided in case a user +// wishes to implement a custom address translation algorithm. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 19.1.1.1 +class uvm_reg_item extends uvm_sequence_item; + + `uvm_object_utils(uvm_reg_item) + + // Variable -- NODOCS -- element_kind + // + // Kind of element being accessed: REG, MEM, or FIELD. See . + // + uvm_elem_kind_e element_kind; + + + // Variable -- NODOCS -- element + // + // A handle to the RegModel model element associated with this transaction. + // Use to determine the type to cast to: , + // , or . + // + uvm_object element; + + + // Variable -- NODOCS -- kind + // + // Kind of access: READ or WRITE. + // + rand uvm_access_e kind; + + + // Variable -- NODOCS -- value + // + // The value to write to, or after completion, the value read from the DUT. + // Burst operations use the property. + // + uvm_reg_data_t value[]; + + + // TODO: parameterize + constraint max_values { value.size() > 0 && value.size() < 1000; } + + // Variable -- NODOCS -- offset + // + // For memory accesses, the offset address. For bursts, + // the ~starting~ offset address. + // + rand uvm_reg_addr_t offset; + + + // Variable -- NODOCS -- status + // + // The result of the transaction: IS_OK, HAS_X, or ERROR. + // See . + // + uvm_status_e status; + + + // Variable -- NODOCS -- local_map + // + // The local map used to obtain addresses. Users may customize + // address-translation using this map. Access to the sequencer + // and bus adapter can be obtained by getting this map's root map, + // then calling and + // . + // + uvm_reg_map local_map; + + + // Variable -- NODOCS -- map + // + // The original map specified for the operation. The actual + // used may differ when a test or sequence written at the block + // level is reused at the system level. + // + uvm_reg_map map; + + + // Variable -- NODOCS -- path + // + // The path being used: or . + // + uvm_door_e path; + + + // Variable -- NODOCS -- parent + // + // The sequence from which the operation originated. + // + rand uvm_sequence_base parent; + + + // Variable -- NODOCS -- prior + // + // The priority requested of this transfer, as defined by + // . + // + int prior = -1; + + + // Variable -- NODOCS -- extension + // + // Handle to optional user data, as conveyed in the call to + // write(), read(), mirror(), or update() used to trigger the operation. + // + rand uvm_object extension; + + + // Variable -- NODOCS -- bd_kind + // + // If path is UVM_BACKDOOR, this member specifies the abstraction + // kind for the backdoor access, e.g. "RTL" or "GATES". + // + string bd_kind; + + + // Variable -- NODOCS -- fname + // + // The file name from where this transaction originated, if provided + // at the call site. + // + string fname; + + + // Variable -- NODOCS -- lineno + // + // The file name from where this transaction originated, if provided + // at the call site. + // + int lineno; + + + + // @uvm-ieee 1800.2-2017 auto 19.1.1.3.1 + function new(string name=""); + super.new(name); + value = new[1]; + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 19.1.1.3.2 + virtual function string convert2string(); + string s,value_s; + s = {"kind=",kind.name(), + " ele_kind=",element_kind.name(), + " ele_name=",element==null?"null":element.get_full_name() }; + + if (value.size() > 1 && uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + value_s = "'{"; + foreach (value[i]) + value_s = {value_s,$sformatf("%0h,",value[i])}; + value_s[value_s.len()-1]="}"; + end + else + value_s = $sformatf("%0h",value[0]); + s = {s, " value=",value_s}; + + if (element_kind == UVM_MEM) + s = {s, $sformatf(" offset=%0h",offset)}; + s = {s," map=",(map==null?"null":map.get_full_name())," path=",path.name()}; + s = {s," status=",status.name()}; + return s; + endfunction + + + // Function -- NODOCS -- do_copy + // + // Copy the ~rhs~ object into this object. The ~rhs~ object must + // derive from . + // + virtual function void do_copy(uvm_object rhs); + uvm_reg_item rhs_; + if (rhs == null) + `uvm_fatal("REG/NULL","do_copy: rhs argument is null") + + if (!$cast(rhs_,rhs)) begin + `uvm_error("WRONG_TYPE","Provided rhs is not of type uvm_reg_item") + return; + end + super.do_copy(rhs); + element_kind = rhs_.element_kind; + element = rhs_.element; + kind = rhs_.kind; + value = rhs_.value; + offset = rhs_.offset; + status = rhs_.status; + local_map = rhs_.local_map; + map = rhs_.map; + path = rhs_.path; + extension = rhs_.extension; + bd_kind = rhs_.bd_kind; + parent = rhs_.parent; + prior = rhs_.prior; + fname = rhs_.fname; + lineno = rhs_.lineno; + endfunction + +endclass + + + + +typedef struct { + + + uvm_access_e kind; + + + + uvm_reg_addr_t addr; + + + + uvm_reg_data_t data; + + + + int n_bits; + + /* + constraint valid_n_bits { + n_bits > 0; + n_bits <= `UVM_REG_DATA_WIDTH; + } + */ + + + + uvm_reg_byte_en_t byte_en; + + + + uvm_status_e status; + +} uvm_reg_bus_op; diff --git a/test_regress/t/t_uvm/reg/uvm_reg_map.svh b/test_regress/t/t_uvm/reg/uvm_reg_map.svh new file mode 100644 index 0000000000..79663a66ea --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_map.svh @@ -0,0 +1,2184 @@ +// ------------------------------------------------------------- +// Copyright 2010-2018 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2014-2017 Intel Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, Inc. +// Copyright 2012 Accellera Systems Initiative +// 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_reg_transaction_order_policy +// Not in LRM. +class uvm_reg_map_info; + uvm_reg_addr_t offset; + string rights; + bit unmapped; + uvm_reg_addr_t addr[]; + uvm_reg_frontdoor frontdoor; + uvm_reg_map_addr_range mem_range; + + // if set marks the uvm_reg_map_info as initialized, prevents using an uninitialized map (for instance if the model + // has not been locked accidently and the maps have not been computed before) + bit is_initialized; +endclass + + +// Class -- NODOCS -- uvm_reg_transaction_order_policy +virtual class uvm_reg_transaction_order_policy extends uvm_object; + function new(string name = "policy"); + super.new(name); + endfunction + + // Function -- NODOCS -- order + // the order() function may reorder the sequence of bus transactions + // produced by a single uvm_reg transaction (read/write). + // This can be used in scenarios when the register width differs from + // the bus width and one register access results in a series of bus transactions. + // the first item (0) of the queue will be the first bus transaction (the last($) + // will be the final transaction + pure virtual function void order(ref uvm_reg_bus_op q[$]); +endclass + +// Extends virtual class uvm_sequence_base so that it can be constructed: +class uvm_reg_seq_base extends uvm_sequence_base; + + `uvm_object_utils(uvm_reg_seq_base) + + +function new(string name = "uvm_reg_seq_base"); + super.new(name); +endfunction + +endclass + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_reg_map +// +// :Address map abstraction class +// +// This class represents an address map. +// An address map is a collection of registers and memories +// accessible via a specific physical interface. +// Address maps can be composed into higher-level address maps. +// +// Address maps are created using the +// method. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.2.1 +class uvm_reg_map extends uvm_object; + + `uvm_object_utils(uvm_reg_map) + + // info that is valid only if top-level map + local uvm_reg_addr_t m_base_addr; + local int unsigned m_n_bytes; + local uvm_endianness_e m_endian; + local bit m_byte_addressing; + local uvm_object_wrapper m_sequence_wrapper; + local uvm_reg_adapter m_adapter; + local uvm_sequencer_base m_sequencer; + local bit m_auto_predict; + local bit m_check_on_read; + + local uvm_reg_block m_parent; + + local int unsigned m_system_n_bytes; + + local uvm_reg_map m_parent_map; + local uvm_reg_addr_t m_submaps[uvm_reg_map]; // value=offset of submap at this level + local string m_submap_rights[uvm_reg_map]; // value=rights of submap at this level + + local uvm_reg_map_info m_regs_info[uvm_reg]; + local uvm_reg_map_info m_mems_info[uvm_mem]; + + local uvm_reg m_regs_by_offset[uvm_reg_addr_t]; + // Use only in addition to above if a RO and a WO + // register share the same address. + local uvm_reg m_regs_by_offset_wo[uvm_reg_addr_t]; + local uvm_mem m_mems_by_offset[uvm_reg_map_addr_range]; + + local uvm_reg_transaction_order_policy policy; + + extern /*local*/ function void Xinit_address_mapX(); + + static local uvm_reg_map m_backdoor; + + + // @uvm-ieee 1800.2-2017 auto 18.2.2 + static function uvm_reg_map backdoor(); + if (m_backdoor == null) + m_backdoor = new("Backdoor"); + return m_backdoor; + endfunction + + + //---------------------- + // Group -- NODOCS -- Initialization + //---------------------- + + + + // @uvm-ieee 1800.2-2017 auto 18.2.3.1 + extern function new(string name="uvm_reg_map"); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.3.2 + extern function void configure(uvm_reg_block parent, + uvm_reg_addr_t base_addr, + int unsigned n_bytes, + uvm_endianness_e endian, + bit byte_addressing = 1); + + + // @uvm-ieee 1800.2-2017 auto 18.2.3.3 + extern virtual function void add_reg (uvm_reg rg, + uvm_reg_addr_t offset, + string rights = "RW", + bit unmapped=0, + uvm_reg_frontdoor frontdoor=null); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.3.4 + extern virtual function void add_mem (uvm_mem mem, + uvm_reg_addr_t offset, + string rights = "RW", + bit unmapped=0, + uvm_reg_frontdoor frontdoor=null); + + + + // NOTE THIS isnt really true because one can add a map only to another map if the + // map parent blocks are either the same or the maps parent is an ancestor of the submaps parent + // also AddressUnitBits needs to match which means essentially that within a block there can only be one + // AddressUnitBits + + // @uvm-ieee 1800.2-2017 auto 18.2.3.5 + extern virtual function void add_submap (uvm_reg_map child_map, + uvm_reg_addr_t offset); + + + // Function -- NODOCS -- set_sequencer + // + // Set the sequencer and adapter associated with this map. This method + // ~must~ be called before starting any sequences based on uvm_reg_sequence. + + // @uvm-ieee 1800.2-2017 auto 18.2.3.6 + extern virtual function void set_sequencer (uvm_sequencer_base sequencer, + uvm_reg_adapter adapter=null); + + + + // Function -- NODOCS -- set_submap_offset + // + // Set the offset of the given ~submap~ to ~offset~. + + // @uvm-ieee 1800.2-2017 auto 18.2.3.8 + extern virtual function void set_submap_offset (uvm_reg_map submap, + uvm_reg_addr_t offset); + + + // Function -- NODOCS -- get_submap_offset + // + // Return the offset of the given ~submap~. + + // @uvm-ieee 1800.2-2017 auto 18.2.3.7 + extern virtual function uvm_reg_addr_t get_submap_offset (uvm_reg_map submap); + + + // Function -- NODOCS -- set_base_addr + // + // Set the base address of this map. + + // @uvm-ieee 1800.2-2017 auto 18.2.3.9 + extern virtual function void set_base_addr (uvm_reg_addr_t offset); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.3.10 + extern virtual function void reset(string kind = "SOFT"); + + + /*local*/ extern virtual function void add_parent_map(uvm_reg_map parent_map, + uvm_reg_addr_t offset); + + /*local*/ extern virtual function void Xverify_map_configX(); + + /*local*/ extern virtual function void m_set_reg_offset(uvm_reg rg, + uvm_reg_addr_t offset, + bit unmapped); + + /*local*/ extern virtual function void m_set_mem_offset(uvm_mem mem, + uvm_reg_addr_t offset, + bit unmapped); + + + //--------------------- + // Group -- NODOCS -- Introspection + //--------------------- + + // Function -- NODOCS -- get_name + // + // Get the simple name + // + // Return the simple object name of this address map. + // + + // Function -- NODOCS -- get_full_name + // + // Get the hierarchical name + // + // Return the hierarchal name of this address map. + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.1 + extern virtual function uvm_reg_map get_root_map(); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.2 + extern virtual function uvm_reg_block get_parent(); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.3 + extern virtual function uvm_reg_map get_parent_map(); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.4 + extern virtual function uvm_reg_addr_t get_base_addr (uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_n_bytes + // + // Get the width in bytes of the bus associated with this map. If ~hier~ + // is ~UVM_HIER~, then gets the effective bus width relative to the system + // level. The effective bus width is the narrowest bus width from this + // map to the top-level root map. Each bus access will be limited to this + // bus width. + // + extern virtual function int unsigned get_n_bytes (uvm_hier_e hier=UVM_HIER); + + + // Function -- NODOCS -- get_addr_unit_bytes + // + // Get the number of bytes in the smallest addressable unit in the map. + // Returns 1 if the address map was configured using byte-level addressing. + // Returns otherwise. + // + extern virtual function int unsigned get_addr_unit_bytes(); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.7 + extern virtual function uvm_endianness_e get_endian (uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.8 + extern virtual function uvm_sequencer_base get_sequencer (uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.9 + extern virtual function uvm_reg_adapter get_adapter (uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.10 + extern virtual function void get_submaps (ref uvm_reg_map maps[$], + input uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.11 + extern virtual function void get_registers (ref uvm_reg regs[$], + input uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.12 + extern virtual function void get_fields (ref uvm_reg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.13 + extern virtual function void get_memories (ref uvm_mem mems[$], + input uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.14 + extern virtual function void get_virtual_registers (ref uvm_vreg regs[$], + input uvm_hier_e hier=UVM_HIER); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.15 + extern virtual function void get_virtual_fields (ref uvm_vreg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + + + extern virtual function uvm_reg_map_info get_reg_map_info(uvm_reg rg, bit error=1); + extern virtual function uvm_reg_map_info get_mem_map_info(uvm_mem mem, bit error=1); + extern virtual function int unsigned get_size(); + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.16 + extern virtual function int get_physical_addresses(uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, + ref uvm_reg_addr_t addr[]); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.17 + extern virtual function uvm_reg get_reg_by_offset(uvm_reg_addr_t offset, + bit read = 1); + + + // @uvm-ieee 1800.2-2017 auto 18.2.4.18 + extern virtual function uvm_mem get_mem_by_offset(uvm_reg_addr_t offset); + + + //------------------ + // Group -- NODOCS -- Bus Access + //------------------ + + + // @uvm-ieee 1800.2-2017 auto 18.2.5.2 + function void set_auto_predict(bit on=1); m_auto_predict = on; endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.2.5.1 + function bit get_auto_predict(); return m_auto_predict; endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.2.5.3 + function void set_check_on_read(bit on=1); + m_check_on_read = on; + foreach (m_submaps[submap]) begin + submap.set_check_on_read(on); + end + endfunction + + + // Function -- NODOCS -- get_check_on_read + // + // Gets the check-on-read mode setting for this map. + // + function bit get_check_on_read(); return m_check_on_read; endfunction + + + + // Task -- NODOCS -- do_bus_write + // + // Perform a bus write operation. + // + extern virtual task do_bus_write (uvm_reg_item rw, + uvm_sequencer_base sequencer, + uvm_reg_adapter adapter); + + + // Task -- NODOCS -- do_bus_read + // + // Perform a bus read operation. + // + extern virtual task do_bus_read (uvm_reg_item rw, + uvm_sequencer_base sequencer, + uvm_reg_adapter adapter); + + + // Task -- NODOCS -- do_write + // + // Perform a write operation. + // + extern virtual task do_write(uvm_reg_item rw); + + + // Task -- NODOCS -- do_read + // + // Perform a read operation. + // + extern virtual task do_read(uvm_reg_item rw); + + extern function void Xget_bus_infoX (uvm_reg_item rw, + output uvm_reg_map_info map_info, + output int size, + output int lsb, + output int addr_skip); + + extern virtual function string convert2string(); + extern virtual function uvm_object clone(); + extern virtual function void do_print (uvm_printer printer); + extern virtual function void do_copy (uvm_object rhs); + //extern virtual function bit do_compare (uvm_object rhs, uvm_comparer comparer); + //extern virtual function void do_pack (uvm_packer packer); + //extern virtual function void do_unpack (uvm_packer packer); + + + + // @uvm-ieee 1800.2-2017 auto 18.2.5.5 + function void set_transaction_order_policy(uvm_reg_transaction_order_policy pol); + policy = pol; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 18.2.5.4 + function uvm_reg_transaction_order_policy get_transaction_order_policy(); + return policy; + endfunction + +// ceil() function +local function automatic int unsigned ceil(int unsigned a, int unsigned b); + int r = a / b; + int r0 = a % b; + return r0 ? (r+1): r; +endfunction + + /* + * translates an access from the current map ~this~ to an address ~base_addr~ (within the current map) with a + * length of ~n_bytes~ into an access from map ~parent_map~. + * if ~mem~ and ~mem_offset~ are supplied then a memory access is assumed + * results: ~addr~ contains the set of addresses and ~byte_offset~ holds the number of bytes the data stream needs to be shifted + * + * this implementation assumes a packed data access + */ + extern virtual function int get_physical_addresses_to_map(uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, // number of bytes + ref uvm_reg_addr_t addr[], // array of addresses + input uvm_reg_map parent_map, // translate till parent_map is the parent of the actual map or NULL if this is a root_map + ref int unsigned byte_offset, + input uvm_mem mem =null + ); + +// performs all bus operations ~accesses~ generated from ~rw~ via adapter ~adapter~ on sequencer ~sequencer~ +extern task perform_accesses(ref uvm_reg_bus_op accesses[$], + input uvm_reg_item rw, + input uvm_reg_adapter adapter, + input uvm_sequencer_base sequencer); + +// performs all necessary bus accesses defined by ~rw~ on the sequencer ~sequencer~ utilizing the adapter ~adapter~ +extern task do_bus_access (uvm_reg_item rw, + uvm_sequencer_base sequencer, + uvm_reg_adapter adapter); + + // unregisters all content from this map recursively + // it is NOT expected that this leads to a fresh new map + // it rather removes all knowledge of this map from other objects + // so that they can be reused with a fresh map instance + // @uvm-ieee 1800.2-2017 auto 18.2.3.11 + virtual function void unregister(); + uvm_reg_block q[$]; + uvm_reg_block::get_root_blocks(q); + + foreach(q[idx]) + q[idx].set_lock(0); + + foreach(q[idx]) + q[idx].unregister(this); + + foreach (m_submaps[map_]) + map_.unregister(); + + m_submaps.delete(); + m_submap_rights.delete(); + + + foreach(m_regs_by_offset[i]) + m_regs_by_offset[i].unregister(this); + + m_regs_by_offset.delete(); + m_regs_by_offset_wo.delete(); + m_mems_by_offset.delete(); + + m_regs_info.delete(); + m_mems_info.delete(); + + m_parent_map =null; + endfunction + + virtual function uvm_reg_map clone_and_update(string rights); + if(m_parent_map!=null) `uvm_error("UVM/REG/CLONEMAPWITHPARENT","cannot clone a map which already has a parent") + if(m_submaps.size() != 0) `uvm_error("UVM/REG/CLONEMAPWITHCHILDREN","cannot clone a map which already has children") + + begin + uvm_reg_map m; + uvm_reg_block b = get_parent(); + uvm_reg qr[$]; + uvm_mem qm[$]; + + m = b.create_map(get_name(),0,m_n_bytes,m_endian,m_byte_addressing); + + foreach(m_regs_by_offset[i]) begin + uvm_reg rg=m_regs_by_offset[i]; + uvm_reg_map_info info = get_reg_map_info(rg); + m.add_reg(rg,info.offset,rights, info.unmapped, info.frontdoor); + end + foreach(m_mems_by_offset[i]) begin + uvm_mem rg=m_mems_by_offset[i]; + uvm_reg_map_info info = get_mem_map_info(rg); + m.add_mem(rg,info.offset,rights, info.unmapped, info.frontdoor); + end + return m; + end + endfunction +endclass: uvm_reg_map + + + +//--------------- +// Initialization +//--------------- + +// new + +function uvm_reg_map::new(string name = "uvm_reg_map"); + super.new((name == "") ? "default_map" : name); + m_auto_predict = 0; + m_check_on_read = 0; +endfunction + + +// configure + +function void uvm_reg_map::configure(uvm_reg_block parent, + uvm_reg_addr_t base_addr, + int unsigned n_bytes, + uvm_endianness_e endian, + bit byte_addressing=1); + m_parent = parent; + m_n_bytes = n_bytes; + m_endian = endian; + m_base_addr = base_addr; + m_byte_addressing = byte_addressing; +endfunction: configure + + +// add_reg + +function void uvm_reg_map::add_reg(uvm_reg rg, + uvm_reg_addr_t offset, + string rights = "RW", + bit unmapped=0, + uvm_reg_frontdoor frontdoor=null); + + if (m_regs_info.exists(rg)) begin + `uvm_error("RegModel", {"Register '",rg.get_name(), + "' has already been added to map '",get_name(),"'"}) + return; + end + + if (rg.get_parent() != get_parent()) begin + `uvm_error("RegModel", + {"Register '",rg.get_full_name(),"' may not be added to address map '", + get_full_name(),"' : they are not in the same block"}) + return; + end + + rg.add_map(this); + + begin + uvm_reg_map_info info = new; + info.offset = offset; + info.rights = rights; + info.unmapped = unmapped; + info.frontdoor = frontdoor; + info.is_initialized=0; + m_regs_info[rg]=info; + end +endfunction + + +// m_set_reg_offset + +function void uvm_reg_map::m_set_reg_offset(uvm_reg rg, + uvm_reg_addr_t offset, + bit unmapped); + + if (!m_regs_info.exists(rg)) begin + `uvm_error("RegModel", + {"Cannot modify offset of register '",rg.get_full_name(), + "' in address map '",get_full_name(), + "' : register not mapped in that address map"}) + return; + end + + begin + uvm_reg_map_info info = m_regs_info[rg]; + uvm_reg_block blk = get_parent(); + uvm_reg_map top_map = get_root_map(); + uvm_reg_addr_t addrs[]; + + // if block is not locked, Xinit_address_mapX will resolve map when block is locked + if (blk.is_locked()) begin + + // remove any existing cached addresses + if (!info.unmapped) begin + foreach (info.addr[i]) begin + + if (!top_map.m_regs_by_offset_wo.exists(info.addr[i])) begin + top_map.m_regs_by_offset.delete(info.addr[i]); + end + else begin + if (top_map.m_regs_by_offset[info.addr[i]] == rg) begin + top_map.m_regs_by_offset[info.addr[i]] = + top_map.m_regs_by_offset_wo[info.addr[i]]; + uvm_reg_read_only_cbs::remove(rg); + uvm_reg_write_only_cbs::remove(top_map.m_regs_by_offset[info.addr[i]]); + end + else begin + uvm_reg_write_only_cbs::remove(rg); + uvm_reg_read_only_cbs::remove(top_map.m_regs_by_offset[info.addr[i]]); + end + top_map.m_regs_by_offset_wo.delete(info.addr[i]); + end + end + end + + // if we are remapping... + if (!unmapped) begin + string rg_acc = rg.Xget_fields_accessX(this); + + // get new addresses + void'(get_physical_addresses(offset,0,rg.get_n_bytes(),addrs)); + + // make sure they do not conflict with others + foreach (addrs[i]) begin + uvm_reg_addr_t addr = addrs[i]; + if (top_map.m_regs_by_offset.exists(addr)) begin + + uvm_reg rg2 = top_map.m_regs_by_offset[addr]; + string rg2_acc = rg2.Xget_fields_accessX(this); + + // If the register at the same address is RO or WO + // and this register is WO or RO, this is OK + if (rg_acc == "RO" && rg2_acc == "WO") begin + top_map.m_regs_by_offset[addr] = rg; + uvm_reg_read_only_cbs::add(rg); + top_map.m_regs_by_offset_wo[addr] = rg2; + uvm_reg_write_only_cbs::add(rg2); + end + else if (rg_acc == "WO" && rg2_acc == "RO") begin + top_map.m_regs_by_offset_wo[addr] = rg; + uvm_reg_write_only_cbs::add(rg); + uvm_reg_read_only_cbs::add(rg2); + end + else begin + string a; + a = $sformatf("%0h",addr); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' register '", + rg.get_full_name(), "' maps to same address as register '", + top_map.m_regs_by_offset[addr].get_full_name(),"': 'h",a}) + end + end + else + top_map.m_regs_by_offset[addr] = rg; + + foreach (top_map.m_mems_by_offset[range]) begin + if (addrs[i] >= range.min && addrs[i] <= range.max) begin + string a; + a = $sformatf("%0h",addrs[i]); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' register '", + rg.get_full_name(), "' overlaps with address range of memory '", + top_map.m_mems_by_offset[range].get_full_name(),"': 'h",a}) + end + end + end + info.addr = addrs; // cache it + end + end + + if (unmapped) begin + info.offset = -1; + info.unmapped = 1; + end + else begin + info.offset = offset; + info.unmapped = 0; + end + + end +endfunction + + +// add_mem + +function void uvm_reg_map::add_mem(uvm_mem mem, + uvm_reg_addr_t offset, + string rights = "RW", + bit unmapped=0, + uvm_reg_frontdoor frontdoor=null); + if (m_mems_info.exists(mem)) begin + `uvm_error("RegModel", {"Memory '",mem.get_name(), + "' has already been added to map '",get_name(),"'"}) + return; + end + + if (mem.get_parent() != get_parent()) begin + `uvm_error("RegModel", + {"Memory '",mem.get_full_name(),"' may not be added to address map '", + get_full_name(),"' : they are not in the same block"}) + return; + end + + mem.add_map(this); + + begin + uvm_reg_map_info info = new; + info.offset = offset; + info.rights = rights; + info.unmapped = unmapped; + info.frontdoor = frontdoor; + m_mems_info[mem] = info; + end +endfunction: add_mem + + + +// m_set_mem_offset + +function void uvm_reg_map::m_set_mem_offset(uvm_mem mem, + uvm_reg_addr_t offset, + bit unmapped); + + if (!m_mems_info.exists(mem)) begin + `uvm_error("RegModel", + {"Cannot modify offset of memory '",mem.get_full_name(), + "' in address map '",get_full_name(), + "' : memory not mapped in that address map"}) + return; + end + + begin + uvm_reg_map_info info = m_mems_info[mem]; + uvm_reg_block blk = get_parent(); + uvm_reg_map top_map = get_root_map(); + uvm_reg_addr_t addrs[]; + + // if block is not locked, Xinit_address_mapX will resolve map when block is locked + if (blk.is_locked()) begin + + // remove any existing cached addresses + if (!info.unmapped) begin + foreach (top_map.m_mems_by_offset[range]) begin + if (top_map.m_mems_by_offset[range] == mem) + top_map.m_mems_by_offset.delete(range); + end + end + + // if we are remapping... + if (!unmapped) begin + uvm_reg_addr_t addrs[],addrs_max[]; + uvm_reg_addr_t min, max, min2, max2; + int unsigned stride; + + void'(get_physical_addresses(offset,0,mem.get_n_bytes(),addrs)); + min = (addrs[0] < addrs[addrs.size()-1]) ? addrs[0] : addrs[addrs.size()-1]; + min2 = addrs[0]; + + void'(get_physical_addresses(offset,(mem.get_size()-1), + mem.get_n_bytes(),addrs_max)); + max = (addrs_max[0] > addrs_max[addrs_max.size()-1]) ? + addrs_max[0] : addrs_max[addrs_max.size()-1]; + max2 = addrs_max[0]; + // address interval between consecutive mem locations + stride = mem.get_n_bytes()/get_addr_unit_bytes(); + + // make sure new offset does not conflict with others + foreach (top_map.m_regs_by_offset[reg_addr]) begin + if (reg_addr >= min && reg_addr <= max) begin + string a,b; + a = $sformatf("[%0h:%0h]",min,max); + b = $sformatf("%0h",reg_addr); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' memory '", + mem.get_full_name(), "' with range ",a, + " overlaps with address of existing register '", + top_map.m_regs_by_offset[reg_addr].get_full_name(),"': 'h",b}) + end + end + + foreach (top_map.m_mems_by_offset[range]) begin + if (min <= range.max && max >= range.max || + min <= range.min && max >= range.min || + min >= range.min && max <= range.max) begin + string a,b; + a = $sformatf("[%0h:%0h]",min,max); + b = $sformatf("[%0h:%0h]",range.min,range.max); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' memory '", + mem.get_full_name(), "' with range ",a, + " overlaps existing memory with range '", + top_map.m_mems_by_offset[range].get_full_name(),"': ",b}) + end + end + + begin + uvm_reg_map_addr_range range = '{ min, max, stride}; + top_map.m_mems_by_offset[range] = mem; + info.addr = addrs; + info.mem_range = range; + end + + end + end + + if (unmapped) begin + info.offset = -1; + info.unmapped = 1; + end + else begin + info.offset = offset; + info.unmapped = 0; + end + + end +endfunction + + +// add_submap + +function void uvm_reg_map::add_submap (uvm_reg_map child_map, + uvm_reg_addr_t offset); + uvm_reg_map parent_map; + + if (child_map == null) begin + `uvm_error("RegModel", {"Attempting to add NULL map to map '",get_full_name(),"'"}) + return; + end + + parent_map = child_map.get_parent_map(); + + // Cannot have more than one parent (currently) + if (parent_map != null) begin + `uvm_error("RegModel", {"Map '", child_map.get_full_name(), + "' is already a child of map '", + parent_map.get_full_name(), + "'. Cannot also be a child of map '", + get_full_name(), + "'"}) + return; + end + + // this check means that n_bytes cannot change in a map hierarchy, that should work with 5446 + begin : n_bytes_match_check + if (m_n_bytes > child_map.get_n_bytes(UVM_NO_HIER)) begin + `uvm_warning("RegModel", + $sformatf("Adding %0d-byte submap '%s' to %0d-byte parent map '%s'", + child_map.get_n_bytes(UVM_NO_HIER), child_map.get_full_name(), + m_n_bytes, get_full_name())) + end + end + + child_map.add_parent_map(this,offset); + + set_submap_offset(child_map, offset); + +endfunction: add_submap + + +// reset + +function void uvm_reg_map::reset(string kind = "SOFT"); + uvm_reg regs[$]; + + get_registers(regs); + + foreach (regs[i]) begin + regs[i].reset(kind); + end +endfunction + + +// add_parent_map + +function void uvm_reg_map::add_parent_map(uvm_reg_map parent_map, uvm_reg_addr_t offset); + + if (parent_map == null) begin + `uvm_error("RegModel", + {"Attempting to add NULL parent map to map '",get_full_name(),"'"}) + return; + end + + if (m_parent_map != null) begin + `uvm_error("RegModel", + $sformatf("Map \"%s\" already a submap of map \"%s\" at offset 'h%h", + get_full_name(), m_parent_map.get_full_name(), + m_parent_map.get_submap_offset(this))) + return; + end + + m_parent_map = parent_map; + parent_map.m_submaps[this] = offset; + +endfunction: add_parent_map + + +// set_sequencer + +function void uvm_reg_map::set_sequencer(uvm_sequencer_base sequencer, + uvm_reg_adapter adapter=null); + + if (sequencer == null) begin + `uvm_error("REG_NULL_SQR", "Null reference specified for bus sequencer") + return; + end + + if (adapter == null) begin + `uvm_info("REG_NO_ADAPT", {"Adapter not specified for map '",get_full_name(), + "'. Accesses via this map will send abstract 'uvm_reg_item' items to sequencer '", + sequencer.get_full_name(),"'"},UVM_MEDIUM) + end + + m_sequencer = sequencer; + m_adapter = adapter; +endfunction + + + +//------------ +// get methods +//------------ + +// get_parent + +function uvm_reg_block uvm_reg_map::get_parent(); + return m_parent; +endfunction + + +// get_parent_map + +function uvm_reg_map uvm_reg_map::get_parent_map(); + return m_parent_map; +endfunction + + +// get_root_map + +function uvm_reg_map uvm_reg_map::get_root_map(); + return (m_parent_map == null) ? this : m_parent_map.get_root_map(); +endfunction: get_root_map + + +// get_base_addr + +function uvm_reg_addr_t uvm_reg_map::get_base_addr(uvm_hier_e hier=UVM_HIER); + uvm_reg_map child = this; + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_base_addr; + get_base_addr = m_parent_map.get_submap_offset(this); + get_base_addr += m_parent_map.get_base_addr(UVM_HIER); +endfunction + + +// get_n_bytes + +function int unsigned uvm_reg_map::get_n_bytes(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER) + return m_n_bytes; + return m_system_n_bytes; +endfunction + + +// get_addr_unit_bytes + +function int unsigned uvm_reg_map::get_addr_unit_bytes(); + return (m_byte_addressing) ? 1 : m_n_bytes; +endfunction + + +// get_endian + +function uvm_endianness_e uvm_reg_map::get_endian(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_endian; + return m_parent_map.get_endian(hier); +endfunction + + +// get_sequencer + +function uvm_sequencer_base uvm_reg_map::get_sequencer(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_sequencer; + return m_parent_map.get_sequencer(hier); +endfunction + + +// get_adapter + +function uvm_reg_adapter uvm_reg_map::get_adapter(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_adapter; + return m_parent_map.get_adapter(hier); +endfunction + + +// get_submaps + +function void uvm_reg_map::get_submaps(ref uvm_reg_map maps[$], input uvm_hier_e hier=UVM_HIER); + + foreach (m_submaps[submap]) + maps.push_back(submap); + + + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_submaps(maps); + end +endfunction + + +// get_registers + +function void uvm_reg_map::get_registers(ref uvm_reg regs[$], input uvm_hier_e hier=UVM_HIER); + + foreach (m_regs_info[rg]) + regs.push_back(rg); + + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_registers(regs); + end + +endfunction + + +// get_fields + +function void uvm_reg_map::get_fields(ref uvm_reg_field fields[$], input uvm_hier_e hier=UVM_HIER); + + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + rg.get_fields(fields); + end + + if (hier == UVM_HIER) + foreach (this.m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_fields(fields); + end + +endfunction + + +// get_memories + +function void uvm_reg_map::get_memories(ref uvm_mem mems[$], input uvm_hier_e hier=UVM_HIER); + + foreach (m_mems_info[mem]) + mems.push_back(mem); + + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_memories(mems); + end + +endfunction + + +// get_virtual_registers + +function void uvm_reg_map::get_virtual_registers(ref uvm_vreg regs[$], input uvm_hier_e hier=UVM_HIER); + + uvm_mem mems[$]; + get_memories(mems,hier); + + foreach (mems[i]) + mems[i].get_virtual_registers(regs); + +endfunction + + +// get_virtual_fields + +function void uvm_reg_map::get_virtual_fields(ref uvm_vreg_field fields[$], input uvm_hier_e hier=UVM_HIER); + + uvm_vreg regs[$]; + get_virtual_registers(regs,hier); + + foreach (regs[i]) + regs[i].get_fields(fields); + +endfunction + + + +// get_full_name + +function string uvm_reg_map::get_full_name(); + if (m_parent == null) + return get_name(); + else + return {m_parent.get_full_name(), ".", get_name()}; +endfunction + + +// get_mem_map_info + +function uvm_reg_map_info uvm_reg_map::get_mem_map_info(uvm_mem mem, bit error=1); + if (!m_mems_info.exists(mem)) begin + if (error) + `uvm_error("REG_NO_MAP",{"Memory '",mem.get_name(),"' not in map '",get_name(),"'"}) + return null; + end + return m_mems_info[mem]; +endfunction + + +// get_reg_map_info + +function uvm_reg_map_info uvm_reg_map::get_reg_map_info(uvm_reg rg, bit error=1); + uvm_reg_map_info result; + if (!m_regs_info.exists(rg)) begin + if (error) + `uvm_error("REG_NO_MAP",{"Register '",rg.get_name(),"' not in map '",get_name(),"'"}) + return null; + end + result = m_regs_info[rg]; + if(!result.is_initialized) + `uvm_warning("RegModel",{"map '",get_name(),"' does not seem to be initialized correctly, check that the top register model is locked()"}) + + return result; +endfunction + + +//---------- +// Size and Overlap Detection +//--------- + +// set_base_addr + +function void uvm_reg_map::set_base_addr(uvm_reg_addr_t offset); + if (m_parent_map != null) begin + m_parent_map.set_submap_offset(this, offset); + end + else begin + m_base_addr = offset; + if (m_parent.is_locked()) begin + uvm_reg_map top_map = get_root_map(); + top_map.Xinit_address_mapX(); + end + end +endfunction + + +// get_size + +function int unsigned uvm_reg_map::get_size(); + + int unsigned max_addr; + int unsigned addr; + + // get max offset from registers + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + addr = m_regs_info[rg].offset + ((rg.get_n_bytes()-1)/m_n_bytes); + if (addr > max_addr) max_addr = addr; + end + + // get max offset from memories + foreach (m_mems_info[mem_]) begin + uvm_mem mem = mem_; + addr = m_mems_info[mem].offset + (mem.get_size() * (((mem.get_n_bytes()-1)/m_n_bytes)+1)) -1; + if (addr > max_addr) max_addr = addr; + end + + // get max offset from submaps + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + addr = m_submaps[submap] + submap.get_size(); + if (addr > max_addr) max_addr = addr; + end + + return max_addr + 1; + +endfunction + + + +function void uvm_reg_map::Xverify_map_configX(); + // Make sure there is a generic payload sequence for each map + // in the model and vice-versa if this is a root sequencer + bit error; + uvm_reg_map root_map = get_root_map(); + + if (root_map.get_adapter() == null) begin + `uvm_error("RegModel", {"Map '",root_map.get_full_name(), + "' does not have an adapter registered"}) + error++; + end + if (root_map.get_sequencer() == null) begin + `uvm_error("RegModel", {"Map '",root_map.get_full_name(), + "' does not have a sequencer registered"}) + error++; + end + if (error) begin + `uvm_fatal("RegModel", {"Must register an adapter and sequencer ", + "for each top-level map in RegModel model"}) + return; + end + +endfunction + +// NOTE: if multiple memory addresses would fall into one bus word then the memory is addressed 'unpacked' +// ie. every memory location will get an own bus address (and bits on the bus larger than the memory width are discarded +// otherwise the memory access is 'packed' +// +// same as get_physical_addresses() but stops at the specified map +function int uvm_reg_map::get_physical_addresses_to_map( + uvm_reg_addr_t base_addr, // in terms of the local map aub + uvm_reg_addr_t mem_offset, // in terms of memory words + int unsigned n_bytes, // number of bytes for the memory stream + ref uvm_reg_addr_t addr[], // out: set of addresses required for memory stream in local map aub + input uvm_reg_map parent_map, // desired target map + ref int unsigned byte_offset, // leading byte offset (due to shifting within address words) + input uvm_mem mem=null + ); + + int bus_width = get_n_bytes(UVM_NO_HIER); + uvm_reg_map up_map; + uvm_reg_addr_t local_addr[]; + uvm_reg_addr_t lbase_addr; + +// `uvm_info("RegModel",$sformatf("this=%p enter base=0x%0x mem_offset=0x%0d request=%0dbytes byte_enable=%0d byte-offset=%0d", +// this,base_addr,mem_offset,n_bytes,m_byte_addressing,byte_offset),UVM_HIGH) + +// `uvm_info("RegModel",$sformatf("addressUnitBits=%0d busWidthBits=%0d",get_addr_unit_bytes()*8,bus_width*8),UVM_HIGH) + + up_map = get_parent_map(); + lbase_addr = up_map==null ? get_base_addr(UVM_NO_HIER): up_map.get_submap_offset(this); +// `uvm_info("RegModel",$sformatf("lbase =0x%0x",lbase_addr),UVM_HIGH) + + if(up_map!=parent_map) begin + uvm_reg_addr_t lb; + // now just translate first address and request same number of bytes + // may need to adjust addr,n_bytes if base_addr*AUB is not a multiple of upmap.AUB + // addr=5,aub=8 and up.aub=16 and n_bytes=1 which is translated addr=2,n_bytes=2 + uvm_reg_addr_t laddr; + begin + // adjust base_addr to find the base of memword(mem_offset) + if(mem_offset) begin + base_addr+=mem_offset*mem.get_n_bytes()/get_addr_unit_bytes(); + end + laddr=lbase_addr + base_addr*get_addr_unit_bytes()/up_map.get_addr_unit_bytes(); // start address in terms of the upper map + lb = (base_addr*get_addr_unit_bytes()) % up_map.get_addr_unit_bytes(); // potential byte offset on top of the start address in the upper map + byte_offset += lb; // accumulate! + end + return up_map.get_physical_addresses_to_map(laddr, 0, n_bytes+lb, addr,parent_map,byte_offset); + end else begin + uvm_reg_addr_t lbase_addr2; + // first need to compute set of addresses + // each address is for one full bus width (the last beat may have less bytes to transfer) + local_addr= new[ceil(n_bytes,bus_width)]; + + lbase_addr2 = base_addr; + if(mem_offset) + if(mem!=null && (mem.get_n_bytes() >= get_addr_unit_bytes())) begin // packed model + lbase_addr2 = base_addr + mem_offset*mem.get_n_bytes()/get_addr_unit_bytes(); + byte_offset += (mem_offset*mem.get_n_bytes() % get_addr_unit_bytes()); + end else begin + lbase_addr2 = base_addr + mem_offset; + end + +// `uvm_info("UVM/REG/ADDR",$sformatf("gen addrs map-aub(bytes)=%0d addrs=%0d map-bus-width(bytes)=%0d lbase_addr2=%0x", +// get_addr_unit_bytes(),local_addr.size(),bus_width,lbase_addr2),UVM_DEBUG) + + case (get_endian(UVM_NO_HIER)) + UVM_LITTLE_ENDIAN: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2 + i*bus_width/get_addr_unit_bytes(); + end + end + UVM_BIG_ENDIAN: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2 + (local_addr.size()-1-i)*bus_width/get_addr_unit_bytes() ; + end + end + UVM_LITTLE_FIFO: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2; + end + end + UVM_BIG_FIFO: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2; + end + end + default: begin + `uvm_error("UVM/REG/MAPNOENDIANESS", + {"Map has no specified endianness. ", + $sformatf("Cannot access %0d bytes register via its %0d byte \"%s\" interface", + n_bytes, bus_width, get_full_name())}) + end + endcase + +// foreach(local_addr[idx]) +// `uvm_info("UVM/REG/ADDR",$sformatf("local_addr idx=%0d addr=%0x",idx,local_addr[idx]),UVM_DEBUG) + + // now need to scale in terms of upper map + + addr = new [local_addr.size()] (local_addr); + foreach(addr[idx]) + addr[idx] += lbase_addr; + +// foreach(addr[idx]) +// `uvm_info("UVM/REG/ADDR",$sformatf("top %0x:",addr[idx]),UVM_DEBUG) + + end +endfunction + +// NOTE the map argument could be made an arg with a default value. didnt do that to present the function signature +function int uvm_reg_map::get_physical_addresses(uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, // number of bytes + ref uvm_reg_addr_t addr[]); + int unsigned skip; + return get_physical_addresses_to_map(base_addr, mem_offset, n_bytes, addr,null,skip); +endfunction + + +//-------------- +// Get-By-Offset +//-------------- + + +// set_submap_offset + +function void uvm_reg_map::set_submap_offset(uvm_reg_map submap, uvm_reg_addr_t offset); + if (submap == null) begin + `uvm_error("REG/NULL","set_submap_offset: submap handle is null") + return; + end + m_submaps[submap] = offset; + if (m_parent.is_locked()) begin + uvm_reg_map root_map = get_root_map(); + root_map.Xinit_address_mapX(); + end +endfunction + + +// get_submap_offset + +function uvm_reg_addr_t uvm_reg_map::get_submap_offset(uvm_reg_map submap); + if (submap == null) begin + `uvm_error("REG/NULL","set_submap_offset: submap handle is null") + return -1; + end + if (!m_submaps.exists(submap)) begin + `uvm_error("RegModel",{"Map '",submap.get_full_name(), + "' is not a submap of '",get_full_name(),"'"}) + return -1; + end + return m_submaps[submap]; +endfunction + + +// get_reg_by_offset + +function uvm_reg uvm_reg_map::get_reg_by_offset(uvm_reg_addr_t offset, + bit read = 1); + if (!m_parent.is_locked()) begin + `uvm_error("RegModel", $sformatf("Cannot get register by offset: Block %s is not locked.", m_parent.get_full_name())) + return null; + end + + if (!read && m_regs_by_offset_wo.exists(offset)) + return m_regs_by_offset_wo[offset]; + + if (m_regs_by_offset.exists(offset)) + return m_regs_by_offset[offset]; + + return null; +endfunction + + +// get_mem_by_offset + +function uvm_mem uvm_reg_map::get_mem_by_offset(uvm_reg_addr_t offset); + if (!m_parent.is_locked()) begin + `uvm_error("RegModel", $sformatf("Cannot memory register by offset: Block %s is not locked.", m_parent.get_full_name())) + return null; + end + + foreach (m_mems_by_offset[range]) begin + if (range.min <= offset && offset <= range.max) begin + return m_mems_by_offset[range]; + end + end + + return null; +endfunction + + +// Xinit_address_mapX + +function void uvm_reg_map::Xinit_address_mapX(); + + int unsigned bus_width; + + uvm_reg_map top_map = get_root_map(); + + if (this == top_map) begin + top_map.m_regs_by_offset.delete(); + top_map.m_regs_by_offset_wo.delete(); + top_map.m_mems_by_offset.delete(); + end + + foreach (m_submaps[l]) begin + uvm_reg_map map=l; + map.Xinit_address_mapX(); + end + + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + m_regs_info[rg].is_initialized=1; + if (!m_regs_info[rg].unmapped) begin + string rg_acc = rg.Xget_fields_accessX(this); + uvm_reg_addr_t addrs[]; + + bus_width = get_physical_addresses(m_regs_info[rg].offset,0,rg.get_n_bytes(),addrs); + + foreach (addrs[i]) begin + uvm_reg_addr_t addr = addrs[i]; + + if (top_map.m_regs_by_offset.exists(addr) && (top_map.m_regs_by_offset[addr] != rg)) begin + + uvm_reg rg2 = top_map.m_regs_by_offset[addr]; + string rg2_acc = rg2.Xget_fields_accessX(this); + + // If the register at the same address is RO or WO + // and this register is WO or RO, this is OK + if (rg_acc == "RO" && rg2_acc == "WO") begin + top_map.m_regs_by_offset[addr] = rg; + uvm_reg_read_only_cbs::add(rg); + top_map.m_regs_by_offset_wo[addr] = rg2; + uvm_reg_write_only_cbs::add(rg2); + end + else if (rg_acc == "WO" && rg2_acc == "RO") begin + top_map.m_regs_by_offset_wo[addr] = rg; + uvm_reg_write_only_cbs::add(rg); + uvm_reg_read_only_cbs::add(rg2); + end + else begin + string a; + a = $sformatf("%0h",addr); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' register '", + rg.get_full_name(), "' maps to same address as register '", + top_map.m_regs_by_offset[addr].get_full_name(),"': 'h",a}) + end + end + else + top_map.m_regs_by_offset[addr] = rg; + + foreach (top_map.m_mems_by_offset[range]) begin + if (addr >= range.min && addr <= range.max) begin + string a,b; + a = $sformatf("%0h",addr); + b = $sformatf("[%0h:%0h]",range.min,range.max); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' register '", + rg.get_full_name(), "' with address ",a, + "maps to same address as memory '", + top_map.m_mems_by_offset[range].get_full_name(),"': ",b}) + end + end + end + m_regs_info[rg].addr = addrs; + end + end + + foreach (m_mems_info[mem_]) begin + uvm_mem mem = mem_; + if (!m_mems_info[mem].unmapped) begin + + uvm_reg_addr_t addrs[],addrs_max[]; + uvm_reg_addr_t min, max, min2, max2; + int unsigned stride; + int unsigned bo; + + bus_width = get_physical_addresses_to_map(m_mems_info[mem].offset,0,mem.get_n_bytes(),addrs,null,bo,mem); + min = (addrs[0] < addrs[addrs.size()-1]) ? addrs[0] : addrs[addrs.size()-1]; + +// foreach(addrs[idx]) +// `uvm_info("UVM/REG/ADDR",$sformatf("idx%0d addr=%0x",idx,addrs[idx]),UVM_DEBUG) + + void'(get_physical_addresses_to_map(m_mems_info[mem].offset,(mem.get_size()-1),mem.get_n_bytes(),addrs_max,null,bo,mem)); + max = (addrs_max[0] > addrs_max[addrs_max.size()-1]) ? addrs_max[0] : addrs_max[addrs_max.size()-1]; + stride = mem.get_n_bytes()/get_addr_unit_bytes(); + +// foreach(addrs_max[idx]) +// `uvm_info("UVM/REG/ADDR",$sformatf("idx%0d addr=%0x",idx,addrs_max[idx]),UVM_DEBUG) + +// `uvm_info("UVM/REG/ADDR",$sformatf("mem %0d x %0d in map aub(bytes)=%0d n_bytes=%0d",mem.get_size(),mem.get_n_bits(), +// get_addr_unit_bytes(),get_n_bytes(UVM_NO_HIER)),UVM_DEBUG) + + /* + if (uvm_report_enabled(UVM_DEBUG, UVM_INFO,"UVM/REG/ADDR")) begin + uvm_reg_addr_t ad[]; + for(int idx=0;idx get_addr_unit_bytes()) + if(mem.get_n_bytes() % get_addr_unit_bytes()) begin + `uvm_warning("UVM/REG/ADDR",$sformatf("memory %s is not matching the word width of the enclosing map %s \ +(one memory word not fitting into k map addresses)", + mem.get_full_name(),get_full_name())) + end + + if(mem.get_n_bytes() < get_addr_unit_bytes()) + if(get_addr_unit_bytes() % mem.get_n_bytes()) + `uvm_warning("UVM/REG/ADDR",$sformatf("the memory %s is not matching the word width of the enclosing map %s \ +(one map address doesnt cover k memory words)", + mem.get_full_name(),get_full_name())) + + if(mem.get_n_bits() % 8) + `uvm_warning("UVM/REG/ADDR",$sformatf("this implementation of UVM requires memory words to be k*8 bits (mem %s \ +has %0d bit words)",mem.get_full_name(),mem.get_n_bits())) + + foreach (top_map.m_regs_by_offset[reg_addr]) begin + if (reg_addr >= min && reg_addr <= max) begin + string a; + a = $sformatf("%0h",reg_addr); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' memory '", + mem.get_full_name(), "' maps to same address as register '", + top_map.m_regs_by_offset[reg_addr].get_full_name(),"': 'h",a}) + end + end + + foreach (top_map.m_mems_by_offset[range]) begin + if (min <= range.max && max >= range.max || + min <= range.min && max >= range.min || + min >= range.min && max <= range.max) + if(top_map.m_mems_by_offset[range]!=mem) // do not warn if the same mem is located at the same address via different paths + begin + string a; + a = $sformatf("[%0h:%0h]",min,max); + `uvm_warning("RegModel", {"In map '",get_full_name(),"' memory '", + mem.get_full_name(), "' overlaps with address range of memory '", + top_map.m_mems_by_offset[range].get_full_name(),"': 'h",a}) + end + end + + begin + uvm_reg_map_addr_range range = '{ min, max, stride}; + top_map.m_mems_by_offset[ range ] = mem; + m_mems_info[mem].addr = addrs; + m_mems_info[mem].mem_range = range; + end + end + end + + // If the block has no registers or memories, + // bus_width won't be set + if (bus_width == 0) bus_width = m_n_bytes; + + m_system_n_bytes = bus_width; +endfunction + + +//----------- +// Bus Access +//----------- + +function void uvm_reg_map::Xget_bus_infoX(uvm_reg_item rw, + output uvm_reg_map_info map_info, + output int size, + output int lsb, + output int addr_skip); + + if (rw.element_kind == UVM_MEM) begin + uvm_mem mem; + if(rw.element == null || !$cast(mem,rw.element)) + `uvm_fatal("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_MEM, ", + "but 'element' does not point to a memory: ",rw.get_name()}) + map_info = get_mem_map_info(mem); + size = mem.get_n_bits(); + end + else if (rw.element_kind == UVM_REG) begin + uvm_reg rg; + if(rw.element == null || !$cast(rg,rw.element)) + `uvm_fatal("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_REG, ", + "but 'element' does not point to a register: ",rw.get_name()}) + map_info = get_reg_map_info(rg); + size = rg.get_n_bits(); + end + else if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field field; + if(rw.element == null || !$cast(field,rw.element)) + `uvm_fatal("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_FIELD, ", + "but 'element' does not point to a field: ",rw.get_name()}) + map_info = get_reg_map_info(field.get_parent()); + size = field.get_n_bits(); + lsb = field.get_lsb_pos(); + addr_skip = lsb/(get_n_bytes()*8); + end +endfunction + + + + +// do_write(uvm_reg_item rw) + +task uvm_reg_map::do_write(uvm_reg_item rw); + + uvm_sequence_base tmp_parent_seq; + uvm_reg_map system_map = get_root_map(); + uvm_reg_adapter adapter = system_map.get_adapter(); + uvm_sequencer_base sequencer = system_map.get_sequencer(); + uvm_reg_seq_base parent_proxy; + + if (adapter != null && adapter.parent_sequence != null) begin + uvm_object o; + uvm_sequence_base seq; + o = adapter.parent_sequence.clone(); + if (o == null) + `uvm_fatal("REG/CLONE", + {"failed to clone adapter's parent sequence: '", + adapter.parent_sequence.get_full_name(), + "' (of type '", + adapter.parent_sequence.get_type_name(), + "')"}) + if (!$cast(seq, o)) + `uvm_fatal("REG/CAST", + {"failed to cast: '", + o.get_full_name(), + "' (of type '", + o.get_type_name(), + "') to uvm_sequence_base!"}) + seq.set_parent_sequence(rw.parent); + rw.parent = seq; + tmp_parent_seq = seq; + end + + if (rw.parent == null) begin + parent_proxy = new("default_parent_seq"); + rw.parent = parent_proxy; + tmp_parent_seq = rw.parent; + end + + if (adapter == null) begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = rw.get_event_pool(); + end_event = ep.get("end") ; + rw.set_sequencer(sequencer); + rw.parent.start_item(rw,rw.prior); + rw.parent.finish_item(rw); + end_event.wait_on(); + end + else begin + do_bus_write(rw, sequencer, adapter); + end + + if (tmp_parent_seq != null) + sequencer.m_sequence_exiting(tmp_parent_seq); + +endtask + + +// do_read(uvm_reg_item rw) + +task uvm_reg_map::do_read(uvm_reg_item rw); + + uvm_sequence_base tmp_parent_seq; + uvm_reg_map system_map = get_root_map(); + uvm_reg_adapter adapter = system_map.get_adapter(); + uvm_sequencer_base sequencer = system_map.get_sequencer(); + uvm_reg_seq_base parent_proxy; + + if (adapter != null && adapter.parent_sequence != null) begin + uvm_object o; + uvm_sequence_base seq; + o = adapter.parent_sequence.clone(); + if (o == null) + `uvm_fatal("REG/CLONE", + {"failed to clone adapter's parent sequence: '", + adapter.parent_sequence.get_full_name(), + "' (of type '", + adapter.parent_sequence.get_type_name(), + "')"}) + if (!$cast(seq, o)) + `uvm_fatal("REG/CAST", + {"failed to cast: '", + o.get_full_name(), + "' (of type '", + o.get_type_name(), + "') to uvm_sequence_base!"}) + seq.set_parent_sequence(rw.parent); + rw.parent = seq; + tmp_parent_seq = seq; + end + + if (rw.parent == null) begin + parent_proxy = new("default_parent_seq"); + rw.parent = parent_proxy; + tmp_parent_seq = rw.parent; + end + + if (adapter == null) begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = rw.get_event_pool(); + end_event = ep.get("end") ; + rw.set_sequencer(sequencer); + rw.parent.start_item(rw,rw.prior); + rw.parent.finish_item(rw); + end_event.wait_on(); + end + else begin + do_bus_read(rw, sequencer, adapter); + end + + if (tmp_parent_seq != null) + sequencer.m_sequence_exiting(tmp_parent_seq); + +endtask + + +// do_bus_write + +task uvm_reg_map::do_bus_write (uvm_reg_item rw, + uvm_sequencer_base sequencer, + uvm_reg_adapter adapter); + + do_bus_access(rw, sequencer, adapter); +endtask + +task uvm_reg_map::perform_accesses(ref uvm_reg_bus_op accesses[$], + input uvm_reg_item rw, + input uvm_reg_adapter adapter, + input uvm_sequencer_base sequencer); + + string op; + uvm_reg_data_logic_t data; + uvm_endianness_e endian; + + op=(rw.kind inside {UVM_READ,UVM_BURST_READ}) ? "Read" : "Wrote"; + endian=get_endian(UVM_NO_HIER); + + // if set utilize the order policy + if(policy!=null) + policy.order(accesses); + + // perform accesses + foreach(accesses[i]) begin + uvm_reg_bus_op rw_access=accesses[i]; + uvm_sequence_item bus_req; + + if ((rw_access.kind == UVM_WRITE) && (endian == UVM_BIG_ENDIAN)) begin + { >> { rw_access.data }} = { << byte { rw_access.data}}; + end + + adapter.m_set_item(rw); + bus_req = adapter.reg2bus(rw_access); + adapter.m_set_item(null); + + if (bus_req == null) + `uvm_fatal("RegMem",{"adapter [",adapter.get_name(),"] didnt return a bus transaction"}) + + bus_req.set_sequencer(sequencer); + rw.parent.start_item(bus_req,rw.prior); + + if (rw.parent != null && i == 0) + rw.parent.mid_do(rw); + + rw.parent.finish_item(bus_req); + begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = bus_req.get_event_pool(); + end_event = ep.get("end") ; + end_event.wait_on(); + end + + if (adapter.provides_responses) begin + uvm_sequence_item bus_rsp; + uvm_access_e op; + // TODO: need to test for right trans type, if not put back in q + rw.parent.get_base_response(bus_rsp,bus_req.get_transaction_id()); + adapter.bus2reg(bus_rsp,rw_access); + end + else begin + adapter.bus2reg(bus_req,rw_access); + end + + if ((rw_access.kind == UVM_READ) && (endian == UVM_BIG_ENDIAN)) begin + { >> { rw_access.data }} = { << byte { rw_access.data}}; + end + + rw.status = rw_access.status; + + begin + data = rw_access.data & ((1<>bit_shift) & 'hff; + p[idx]=n; + end + if(extra_byte) + p.push_back(ac); + end + +/* + if (uvm_report_enabled(UVM_DEBUG, UVM_INFO, "UVM/REG/ADDR")) begin + foreach(be[idx]) + `uvm_info("UVM/REG/ADDR",$sformatf("idx %0d en=%0d",idx,be[idx]),UVM_DEBUG) + + foreach(adr[idx]) + `uvm_info("UVM/REG/ADDR",$sformatf("mem-adr %0x byte-offset=%0d",adr[idx],byte_offset),UVM_DEBUG) + + foreach(p[idx]) + `uvm_info("UVM/REG/ADDR",$sformatf("idx %0d data=%x enable=%0d",idx,p[idx],be[idx]),UVM_DEBUG) + + foreach(rw.value[idx]) + `uvm_info("UVM/REG/ADDR",$sformatf("original idx=%0d %0x",idx,rw.value[idx]),UVM_DEBUG) + + end +*/ + + // transform into accesses per address + accesses.delete(); + foreach(adr[i]) begin + uvm_reg_bus_op rw_access; + uvm_reg_data_t data; + + for(int i0=0;i0=0;i--) begin + if(rw_access.byte_en[i]==0) + rw_access.n_bits-=8; + else + break; + end + + accesses.push_back(rw_access); + end + + perform_accesses(accesses, rw, adapter, sequencer); + + // for reads copy back to rw.value + if(rw.kind inside {UVM_READ,UVM_BURST_READ}) begin + p.delete(); + foreach(accesses[i0]) + for(int i1=0;i1 bits +// +typedef bit unsigned [`UVM_REG_DATA_WIDTH-1:0] uvm_reg_data_t ; + + +// Type -- NODOCS -- uvm_reg_data_logic_t +// +// 4-state data value with <`UVM_REG_DATA_WIDTH> bits +// +typedef logic unsigned [`UVM_REG_DATA_WIDTH-1:0] uvm_reg_data_logic_t ; + + +// Type -- NODOCS -- uvm_reg_addr_t +// +// 2-state address value with <`UVM_REG_ADDR_WIDTH> bits +// +typedef bit unsigned [`UVM_REG_ADDR_WIDTH-1:0] uvm_reg_addr_t ; + + +// Type -- NODOCS -- uvm_reg_addr_logic_t +// +// 4-state address value with <`UVM_REG_ADDR_WIDTH> bits +// +typedef logic unsigned [`UVM_REG_ADDR_WIDTH-1:0] uvm_reg_addr_logic_t ; + + +// Type -- NODOCS -- uvm_reg_byte_en_t +// +// 2-state byte_enable value with <`UVM_REG_BYTENABLE_WIDTH> bits +// +typedef bit unsigned [`UVM_REG_BYTENABLE_WIDTH-1:0] uvm_reg_byte_en_t ; + + +// Type -- NODOCS -- uvm_reg_cvr_t +// +// Coverage model value set with <`UVM_REG_CVR_WIDTH> bits. +// +// Symbolic values for individual coverage models are defined +// by the type. +// +// The following bits in the set are assigned as follows +// +// 0-7 - UVM pre-defined coverage models +// 8-15 - Coverage models defined by EDA vendors, +// implemented in a register model generator. +// 16-23 - User-defined coverage models +// 24.. - Reserved +// +typedef bit [`UVM_REG_CVR_WIDTH-1:0] uvm_reg_cvr_t ; + + +// Type -- NODOCS -- uvm_hdl_path_slice +// +// Slice of an HDL path +// +// Struct that specifies the HDL variable that corresponds to all +// or a portion of a register. +// +// path - Path to the HDL variable. +// offset - Offset of the LSB in the register that this variable implements +// size - Number of bits (toward the MSB) that this variable implements +// +// If the HDL variable implements all of the register, ~offset~ and ~size~ +// are specified as -1. For example: +//| +//| r1.add_hdl_path('{ '{"r1", -1, -1} }); +//| +// +typedef struct { + string path; + int offset; + int size; +} uvm_hdl_path_slice; + + +typedef uvm_resource_db#(uvm_reg_cvr_t) uvm_reg_cvr_rsrc_db; + + +//-------------------- +// Group -- NODOCS -- Enumerations +//-------------------- + +// Enum -- NODOCS -- uvm_status_e +// +// Return status for register operations +// +// UVM_IS_OK - Operation completed successfully +// UVM_NOT_OK - Operation completed with error +// UVM_HAS_X - Operation completed successfully bit had unknown bits. +// + + typedef enum { + UVM_IS_OK, + UVM_NOT_OK, + UVM_HAS_X + } uvm_status_e; + + +// Enum -- NODOCS -- uvm_door_e +// +// Path used for register operation +// +// UVM_FRONTDOOR - Use the front door +// UVM_BACKDOOR - Use the back door +// UVM_PREDICT - Operation derived from observations by a bus monitor via +// the class. +// UVM_DEFAULT_DOOR - Operation specified by the context +// + + typedef enum { + UVM_FRONTDOOR, + UVM_BACKDOOR, + UVM_PREDICT, + UVM_DEFAULT_DOOR + } uvm_door_e; + +`ifdef UVM_ENABLE_DEPRECATED_API + typedef uvm_door_e uvm_path_e; + parameter uvm_path_e UVM_DEFAULT_PATH = UVM_DEFAULT_DOOR; +`endif + +// Enum -- NODOCS -- uvm_check_e +// +// Read-only or read-and-check +// +// UVM_NO_CHECK - Read only +// UVM_CHECK - Read and check +// + typedef enum { + UVM_NO_CHECK, + UVM_CHECK + } uvm_check_e; + + +// Enum -- NODOCS -- uvm_endianness_e +// +// Specifies byte ordering +// +// UVM_NO_ENDIAN - Byte ordering not applicable +// UVM_LITTLE_ENDIAN - Least-significant bytes first in consecutive addresses +// UVM_BIG_ENDIAN - Most-significant bytes first in consecutive addresses +// UVM_LITTLE_FIFO - Least-significant bytes first at the same address +// UVM_BIG_FIFO - Most-significant bytes first at the same address +// + typedef enum { + UVM_NO_ENDIAN, + UVM_LITTLE_ENDIAN, + UVM_BIG_ENDIAN, + UVM_LITTLE_FIFO, + UVM_BIG_FIFO + } uvm_endianness_e; + + +// Enum -- NODOCS -- uvm_elem_kind_e +// +// Type of element being read or written +// +// UVM_REG - Register +// UVM_FIELD - Field +// UVM_MEM - Memory location +// + typedef enum { + UVM_REG, + UVM_FIELD, + UVM_MEM + } uvm_elem_kind_e; + + +// Enum -- NODOCS -- uvm_access_e +// +// Type of operation begin performed +// +// UVM_READ - Read operation +// UVM_WRITE - Write operation +// + typedef enum { + UVM_READ, + UVM_WRITE, + UVM_BURST_READ, + UVM_BURST_WRITE + } uvm_access_e; + + +// Enum -- NODOCS -- uvm_hier_e +// +// Whether to provide the requested information from a hierarchical context. +// +// UVM_NO_HIER - Provide info from the local context +// UVM_HIER - Provide info based on the hierarchical context + + typedef enum { + UVM_NO_HIER, + UVM_HIER + } uvm_hier_e; + + +// Enum -- NODOCS -- uvm_predict_e +// +// How the mirror is to be updated +// +// UVM_PREDICT_DIRECT - Predicted value is as-is +// UVM_PREDICT_READ - Predict based on the specified value having been read +// UVM_PREDICT_WRITE - Predict based on the specified value having been written +// + typedef enum { + UVM_PREDICT_DIRECT, + UVM_PREDICT_READ, + UVM_PREDICT_WRITE + } uvm_predict_e; + + +// Enum -- NODOCS -- uvm_coverage_model_e +// +// Coverage models available or desired. +// Multiple models may be specified by bitwise OR'ing individual model identifiers. +// +// UVM_NO_COVERAGE - None +// UVM_CVR_REG_BITS - Individual register bits +// UVM_CVR_ADDR_MAP - Individual register and memory addresses +// UVM_CVR_FIELD_VALS - Field values +// UVM_CVR_ALL - All coverage models +// + typedef enum uvm_reg_cvr_t { + UVM_NO_COVERAGE = 'h0000, + UVM_CVR_REG_BITS = 'h0001, + UVM_CVR_ADDR_MAP = 'h0002, + UVM_CVR_FIELD_VALS = 'h0004, + UVM_CVR_ALL = -1 + } uvm_coverage_model_e; + + +// Enum -- NODOCS -- uvm_reg_mem_tests_e +// +// Select which pre-defined test sequence to execute. +// +// Multiple test sequences may be selected by bitwise OR'ing their +// respective symbolic values. +// +// UVM_DO_REG_HW_RESET - Run +// UVM_DO_REG_BIT_BASH - Run +// UVM_DO_REG_ACCESS - Run +// UVM_DO_MEM_ACCESS - Run +// UVM_DO_SHARED_ACCESS - Run +// UVM_DO_MEM_WALK - Run +// UVM_DO_ALL_REG_MEM_TESTS - Run all of the above +// +// Test sequences, when selected, are executed in the +// order in which they are specified above. +// +typedef enum bit [63:0] { + UVM_DO_REG_HW_RESET = 64'h0000_0000_0000_0001, + UVM_DO_REG_BIT_BASH = 64'h0000_0000_0000_0002, + UVM_DO_REG_ACCESS = 64'h0000_0000_0000_0004, + UVM_DO_MEM_ACCESS = 64'h0000_0000_0000_0008, + UVM_DO_SHARED_ACCESS = 64'h0000_0000_0000_0010, + UVM_DO_MEM_WALK = 64'h0000_0000_0000_0020, + UVM_DO_ALL_REG_MEM_TESTS = 64'hffff_ffff_ffff_ffff +} uvm_reg_mem_tests_e; + + + +//----------------------- +// Group -- NODOCS -- Utility Classes +//----------------------- + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_hdl_path_concat +// +// Concatenation of HDL variables +// +// A dArray of specifying a concatenation +// of HDL variables that implement a register in the HDL. +// +// Slices must be specified in most-to-least significant order. +// Slices must not overlap. Gaps may exist in the concatenation +// if portions of the registers are not implemented. +// +// For example, the following register +//| +//| 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 +//| Bits: 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +//| +-+---+-------------+---+-------+ +//| |A|xxx| B |xxx| C | +//| +-+---+-------------+---+-------+ +//| +// +// If the register is implemented using a single HDL variable, +// The array should specify a single slice with its ~offset~ and ~size~ +// specified as -1. For example: +// +//| concat.set('{ '{"r1", -1, -1} }); +// +//------------------------------------------------------------------------------ + +class uvm_hdl_path_concat; + + // Variable -- NODOCS -- slices + // Array of individual slices, + // stored in most-to-least significant order + uvm_hdl_path_slice slices[]; + + // Function -- NODOCS -- set + // Initialize the concatenation using an array literal + function void set(uvm_hdl_path_slice t[]); + slices = t; + endfunction + + // Function -- NODOCS -- add_slice + // Append the specified ~slice~ literal to the path concatenation + function void add_slice(uvm_hdl_path_slice slice); + slices = new [slices.size()+1] (slices); + slices[slices.size()-1] = slice; + endfunction + + // Function -- NODOCS -- add_path + // Append the specified ~path~ to the path concatenation, + // for the specified number of bits at the specified ~offset~. + function void add_path(string path, + int unsigned offset = -1, + int unsigned size = -1); + uvm_hdl_path_slice t; + t.offset = offset; + t.path = path; + t.size = size; + + add_slice(t); + endfunction + +endclass + + + + +// concat2string + +function automatic string uvm_hdl_concat2string(uvm_hdl_path_concat concat); + string image = "{"; + + if (concat.slices.size() == 1 && + concat.slices[0].offset == -1 && + concat.slices[0].size == -1) + return concat.slices[0].path; + + foreach (concat.slices[i]) begin + uvm_hdl_path_slice slice=concat.slices[i]; + + image = { image, (i == 0) ? "" : ", ", slice.path }; + if (slice.offset >= 0) + image = { image, "@", $sformatf("[%0d +: %0d]", slice.offset, slice.size) }; + end + + image = { image, "}" }; + + return image; +endfunction + +typedef struct packed { + uvm_reg_addr_t min; + uvm_reg_addr_t max; + int unsigned stride; + } uvm_reg_map_addr_range; + + +`include "reg/uvm_reg_item.svh" +`include "reg/uvm_reg_adapter.svh" +`include "reg/uvm_reg_predictor.svh" +`include "reg/uvm_reg_sequence.svh" +`include "reg/uvm_reg_cbs.svh" +`include "reg/uvm_reg_backdoor.svh" +`include "reg/uvm_reg_field.svh" +`include "reg/uvm_vreg_field.svh" +`include "reg/uvm_reg.svh" +`include "reg/uvm_reg_indirect.svh" +`include "reg/uvm_reg_fifo.svh" +`include "reg/uvm_reg_file.svh" +`include "reg/uvm_mem_mam.svh" +`include "reg/uvm_vreg.svh" +`include "reg/uvm_mem.svh" +`include "reg/uvm_reg_map.svh" +`include "reg/uvm_reg_block.svh" + +`include "reg/sequences/uvm_reg_hw_reset_seq.svh" +`include "reg/sequences/uvm_reg_bit_bash_seq.svh" +`include "reg/sequences/uvm_mem_walk_seq.svh" +`include "reg/sequences/uvm_mem_access_seq.svh" +`include "reg/sequences/uvm_reg_access_seq.svh" +`include "reg/sequences/uvm_reg_mem_shared_access_seq.svh" +`include "reg/sequences/uvm_reg_mem_built_in_seq.svh" +`include "reg/sequences/uvm_reg_mem_hdl_paths_seq.svh" + +`endif // UVM_REG_MODEL__SV diff --git a/test_regress/t/t_uvm/reg/uvm_reg_predictor.svh b/test_regress/t/t_uvm/reg/uvm_reg_predictor.svh new file mode 100644 index 0000000000..bd0294d5f1 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_predictor.svh @@ -0,0 +1,287 @@ +// +// ------------------------------------------------------------- +// Copyright 2014 Semifore +// Copyright 2004-2011 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// 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. +// ------------------------------------------------------------- +// + + +//------------------------------------------------------------------------------ +// TITLE -- NODOCS -- Explicit Register Predictor +//------------------------------------------------------------------------------ +// +// The class defines a predictor component, +// which is used to update the register model's mirror values +// based on transactions explicitly observed on a physical bus. +//------------------------------------------------------------------------------ + +class uvm_predict_s; + bit addr[uvm_reg_addr_t]; + uvm_reg_item reg_item; +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_reg_predictor +// +// Updates the register model mirror based on observed bus transactions +// +// This class converts observed bus transactions of type ~BUSTYPE~ to generic +// registers transactions, determines the register being accessed based on the +// bus address, then updates the register's mirror value with the observed bus +// data, subject to the register's access mode. See for details. +// +// Memories can be large, so their accesses are not predicted. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 19.3.1 +class uvm_reg_predictor #(type BUSTYPE=int) extends uvm_component; + + `uvm_component_param_utils(uvm_reg_predictor#(BUSTYPE)) + + // Variable -- NODOCS -- bus_in + // + // Observed bus transactions of type ~BUSTYPE~ are received from this + // port and processed. + // + // For each incoming transaction, the predictor will attempt to get the + // register or memory handle corresponding to the observed bus address. + // + // If there is a match, the predictor calls the register or memory's + // predict method, passing in the observed bus data. The register or + // memory mirror will be updated with this data, subject to its configured + // access behavior--RW, RO, WO, etc. The predictor will also convert the + // bus transaction to a generic and send it out the + // ~reg_ap~ analysis port. + // + // If the register is wider than the bus, the + // predictor will collect the multiple bus transactions needed to + // determine the value being read or written. + // + uvm_analysis_imp #(BUSTYPE, uvm_reg_predictor #(BUSTYPE)) bus_in; + + + // Variable -- NODOCS -- reg_ap + // + // Analysis output port that publishes transactions + // converted from bus transactions received on ~bus_in~. + uvm_analysis_port #(uvm_reg_item) reg_ap; + + + // Variable -- NODOCS -- map + // + // The map used to convert a bus address to the corresponding register + // or memory handle. Must be configured before the run phase. + // + uvm_reg_map map; + + + // Variable -- NODOCS -- adapter + // + // The adapter used to convey the parameters of a bus operation in + // terms of a canonical datum. + // The must be configured before the run phase. + // + uvm_reg_adapter adapter; + + + + // @uvm-ieee 1800.2-2017 auto 19.3.3.1 + function new (string name, uvm_component parent); + super.new(name, parent); + bus_in = new("bus_in", this); + reg_ap = new("reg_ap", this); + endfunction + + // This method is documented in uvm_object +`ifdef UVM_ENABLE_DEPRECATED_API + static string type_name = ""; + virtual function string get_type_name(); + if (type_name == "") begin + BUSTYPE t; + `ifdef VERILATOR + t = BUSTYPE::type_id_create("t"); + `else + t = BUSTYPE::type_id::create("t"); + `endif + type_name = {"uvm_reg_predictor #(", t.get_type_name(), ")"}; + end + return type_name; + endfunction +`else // !`ifdef UVM_ENABLE_DEPRECATED_API + // TODO: Is it better to replace this with: + //| `uvm_type_name_decl($sformatf("uvm_reg_predictor #(%s)", BUSTYPE::type_name()) + static function string type_name(); + static string m_type_name; + if (m_type_name == "") begin + BUSTYPE t; + `ifdef VERILATOR + t = BUSTYPE::type_id_create("t"); + `else + t = BUSTYPE::type_id::create("t"); + `endif + m_type_name = {"uvm_reg_predictor #(", t.get_type_name(), ")"}; + end + return m_type_name; + endfunction // type_name + virtual function string get_type_name(); + return type_name(); + endfunction : get_type_name + +`endif // !`ifdef UVM_ENABLE_DEPRECATED_API + + // @uvm-ieee 1800.2-2017 auto 19.3.3.2 + virtual function void pre_predict(uvm_reg_item rw); + endfunction + + local uvm_predict_s m_pending[uvm_reg]; + + + // Function- write + // + // not a user-level method. Do not call directly. See documentation + // for the ~bus_in~ member. + // + virtual function void write(BUSTYPE tr); + uvm_reg rg; + uvm_reg_bus_op rw; + if (adapter == null) + `uvm_fatal("REG/WRITE/NULL","write: adapter handle is null") + + // In case they forget to set byte_en + rw.byte_en = -1; + adapter.bus2reg(tr,rw); + rg = map.get_reg_by_offset(rw.addr, (rw.kind == UVM_READ)); + + // ToDo: Add memory look-up and call + + if (rg != null) begin + bit found; + uvm_reg_item reg_item; + uvm_reg_map local_map; + uvm_reg_map_info map_info; + uvm_predict_s predict_info; + uvm_reg_indirect_data ireg; + uvm_reg ir; + + if (!m_pending.exists(rg)) begin + uvm_reg_item item = new; + predict_info =new; + item.element_kind = UVM_REG; + item.element = rg; + item.path = UVM_PREDICT; + item.map = map; + item.kind = rw.kind; + predict_info.reg_item = item; + m_pending[rg] = predict_info; + end + predict_info = m_pending[rg]; + reg_item = predict_info.reg_item; + + if (predict_info.addr.exists(rw.addr)) begin + `uvm_error("REG_PREDICT_COLLISION",{"Collision detected for register '", + rg.get_full_name(),"'"}) + // TODO: what to do with subsequent collisions? + m_pending.delete(rg); + end + + local_map = rg.get_local_map(map); + map_info = local_map.get_reg_map_info(rg); + ir=($cast(ireg, rg))?ireg.get_indirect_reg():rg; + + foreach (map_info.addr[i]) begin + if (rw.addr == map_info.addr[i]) begin + found = 1; + reg_item.value[0] |= rw.data << (i * map.get_n_bytes()*8); + predict_info.addr[rw.addr] = 1; + if (predict_info.addr.num() == map_info.addr.size()) begin + // We've captured the entire abstract register transaction. + uvm_predict_e predict_kind = + (reg_item.kind == UVM_WRITE) ? UVM_PREDICT_WRITE : UVM_PREDICT_READ; + + if (reg_item.kind == UVM_READ && + local_map.get_check_on_read() && + reg_item.status != UVM_NOT_OK) begin + void'(rg.do_check(ir.get_mirrored_value(), reg_item.value[0], local_map)); + end + + pre_predict(reg_item); + + ir.XsampleX(reg_item.value[0], rw.byte_en, + reg_item.kind == UVM_READ, local_map); + begin + uvm_reg_block blk = rg.get_parent(); + blk.XsampleX(map_info.offset, + reg_item.kind == UVM_READ, + local_map); + end + + rg.do_predict(reg_item, predict_kind, rw.byte_en); + if(reg_item.kind == UVM_WRITE) + `uvm_info("REG_PREDICT", {"Observed WRITE transaction to register ", + ir.get_full_name(), ": value='h", + $sformatf("%0h",reg_item.value[0]), " : updated value = 'h", + $sformatf("%0h",ir.get())},UVM_HIGH) + else + `uvm_info("REG_PREDICT", {"Observed READ transaction to register ", + ir.get_full_name(), ": value='h", + $sformatf("%0h",reg_item.value[0])},UVM_HIGH) + reg_ap.write(reg_item); + m_pending.delete(rg); + end + break; + end + end + if (!found) + `uvm_error("REG_PREDICT_INTERNAL",{"Unexpected failed address lookup for register '", + rg.get_full_name(),"'"}) + end + else begin + `uvm_info("REG_PREDICT_NOT_FOR_ME", + {"Observed transaction does not target a register: ", + $sformatf("%p",tr)},UVM_FULL) + end + endfunction + + + // Function -- NODOCS -- check_phase + // + // Checks that no pending register transactions are still queued. + + // @uvm-ieee 1800.2-2017 auto 19.3.3.3 + virtual function void check_phase(uvm_phase phase); + string q[$]; + super.check_phase(phase); + + foreach (m_pending[l]) begin + uvm_reg rg=l; + q.push_back($sformatf("\n%s",rg.get_full_name())); + end + + if (m_pending.num() > 0) begin + `uvm_error("PENDING REG ITEMS", + $sformatf("There are %0d incomplete register transactions still pending completion:%s",m_pending.num(),`UVM_STRING_QUEUE_STREAMING_PACK(q))) + + end + endfunction + +endclass diff --git a/test_regress/t/t_uvm/reg/uvm_reg_sequence.svh b/test_regress/t/t_uvm/reg/uvm_reg_sequence.svh new file mode 100644 index 0000000000..95a5306d12 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_reg_sequence.svh @@ -0,0 +1,425 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + + +//------------------------------------------------------------------------------ +// TITLE -- NODOCS -- Register Sequence Classes +//------------------------------------------------------------------------------ +// +// This section defines the base classes used for register stimulus generation. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_reg_sequence +// +// This class provides base functionality for both user-defined RegModel test +// sequences and "register translation sequences". +// +// - When used as a base for user-defined RegModel test sequences, this class +// provides convenience methods for reading and writing registers and +// memories. Users implement the body() method to interact directly with +// the RegModel model (held in the property) or indirectly via the +// delegation methods in this class. +// +// - When used as a translation sequence, objects of this class are +// executed directly on a bus sequencer which are used in support of a layered sequencer +// use model, a pre-defined convert-and-execute algorithm is provided. +// +// Register operations do not require extending this class if none of the above +// services are needed. Register test sequences can be extend from the base +// base class or even from outside a sequence. +// +// Note- The convenience API not yet implemented. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 19.4.1.1 +class uvm_reg_sequence #(type BASE=uvm_sequence #(uvm_reg_item)) extends BASE; + + `uvm_object_param_utils(uvm_reg_sequence #(BASE)) + + // Parameter -- NODOCS -- BASE + // + // Specifies the sequence type to extend from. + // + // When used as a translation sequence running on a bus sequencer, ~BASE~ must + // be compatible with the sequence type expected by the bus sequencer. + // + // When used as a test sequence running on a particular sequencer, ~BASE~ + // must be compatible with the sequence type expected by that sequencer. + // + // When used as a virtual test sequence without a sequencer, ~BASE~ does + // not need to be specified, i.e. the default specialization is adequate. + // + // To maximize opportunities for reuse, user-defined RegModel sequences should + // "promote" the BASE parameter. + // + // | class my_reg_sequence #(type BASE=uvm_sequence #(uvm_reg_item)) + // | extends uvm_reg_sequence #(BASE); + // + // This way, the RegModel sequence can be extended from + // user-defined base sequences. + + + // Variable -- NODOCS -- model + // + // Block abstraction this sequence executes on, defined only when this + // sequence is a user-defined test sequence. + // + uvm_reg_block model; + + + // Variable -- NODOCS -- adapter + // + // Adapter to use for translating between abstract register transactions + // and physical bus transactions, defined only when this sequence is a + // translation sequence. + // + uvm_reg_adapter adapter; + + + // Variable -- NODOCS -- reg_seqr + // + // Layered upstream "register" sequencer. + // + // Specifies the upstream sequencer between abstract register transactions + // and physical bus transactions. Defined only when this sequence is a + // translation sequence, and we want to "pull" from an upstream sequencer. + // +`ifdef VERILATOR + uvm_sequencer #(uvm_reg_item, uvm_reg_item) reg_seqr; +`else + uvm_sequencer #(uvm_reg_item) reg_seqr; +`endif + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.4.1 + function new (string name="uvm_reg_sequence_inst"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.4.2 + virtual task body(); + if (m_sequencer == null) begin + `uvm_fatal("NO_SEQR", {"Sequence executing as translation sequence, ", + "but is not associated with a sequencer (m_sequencer == null)"}) + end + if (reg_seqr == null) begin + `uvm_warning("REG_XLATE_NO_SEQR", + {"Executing RegModel translation sequence on sequencer ", + m_sequencer.get_full_name(),"' does not have an upstream sequencer defined. ", + "Execution of register items available only via direct calls to 'do_reg_item'"}) + wait(0); + end + `uvm_info("REG_XLATE_SEQ_START", + {"Starting RegModel translation sequence on sequencer ", + m_sequencer.get_full_name(),"'"},UVM_LOW) + forever begin + uvm_reg_item reg_item; + reg_seqr.peek(reg_item); + do_reg_item(reg_item); + reg_seqr.get(reg_item); + #0; + end + endtask + + + typedef enum { LOCAL, UPSTREAM } seq_parent_e; + + seq_parent_e parent_select = LOCAL; + + uvm_sequence_base upstream_parent; + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.4.3 + virtual task do_reg_item(uvm_reg_item rw); + string rws=rw.convert2string(); + if (m_sequencer == null) + `uvm_fatal("REG/DO_ITEM/NULL","do_reg_item: m_sequencer is null") + if (adapter == null) + `uvm_fatal("REG/DO_ITEM/NULL","do_reg_item: adapter handle is null") + + `uvm_info("DO_RW_ACCESS",{"Doing transaction: ",rws},UVM_HIGH) + + if (parent_select == LOCAL) begin + upstream_parent = rw.parent; + rw.parent = this; + end + + if (rw.kind == UVM_WRITE) + rw.local_map.do_bus_write(rw, m_sequencer, adapter); + else + rw.local_map.do_bus_read(rw, m_sequencer, adapter); + + if (parent_select == LOCAL) + rw.parent = upstream_parent; + endtask + + + //---------------------------------- + // Group -- NODOCS -- Convenience Write/Read API + //---------------------------------- + // + // The following methods delegate to the corresponding method in the + // register or memory element. They allow a sequence ~body()~ to do + // reads and writes without having to explicitly supply itself to + // ~parent~ sequence argument. Thus, a register write + // + //| model.regA.write(status, value, .parent(this)); + // + // can be written instead as + // + //| write_reg(model.regA, status, value); + // + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.1 + virtual task write_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + `uvm_error("NO_REG","Register argument is null") + else + rg.write(status,value,path,map,this,prior,extension,fname,lineno); + endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.2 + virtual task read_reg(input uvm_reg rg, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + `uvm_error("NO_REG","Register argument is null") + else + rg.read(status,value,path,map,this,prior,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.3 + virtual task poke_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + `uvm_error("NO_REG","Register argument is null") + else + rg.poke(status,value,kind,this,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.4 + virtual task peek_reg(input uvm_reg rg, + output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + `uvm_error("NO_REG","Register argument is null") + else + rg.peek(status,value,kind,this,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.5 + virtual task update_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + `uvm_error("NO_REG","Register argument is null") + else + rg.update(status,path,map,this,prior,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.6 + virtual task mirror_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + `uvm_error("NO_REG","Register argument is null") + else + rg.mirror(status,check,path,map,this,prior,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.7 + virtual task write_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + `uvm_error("NO_MEM","Memory argument is null") + else + mem.write(status,offset,value,path,map,this,prior,extension,fname,lineno); + endtask + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.8 + virtual task read_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + `uvm_error("NO_MEM","Memory argument is null") + else + mem.read(status,offset,value,path,map,this,prior,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.9 + virtual task poke_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + `uvm_error("NO_MEM","Memory argument is null") + else + mem.poke(status,offset,value,kind,this,extension,fname,lineno); + endtask + + + + + // @uvm-ieee 1800.2-2017 auto 19.4.1.5.10 + virtual task peek_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + `uvm_error("NO_MEM","Memory argument is null") + else + mem.peek(status,offset,value,kind,this,extension,fname,lineno); + endtask + + + // Function- put_response + // + // not user visible. Needed to populate this sequence's response + // queue with any bus item type. + // + virtual function void put_response(uvm_sequence_item response_item); + put_base_response(response_item); + endfunction + +endclass + + + +// @uvm-ieee 1800.2-2017 auto 19.4.2.1 +virtual class uvm_reg_frontdoor extends uvm_reg_sequence #(uvm_sequence #(uvm_sequence_item)); + + `uvm_object_abstract_utils(uvm_reg_frontdoor) + + + // Variable -- NODOCS -- rw_info + // + // Holds information about the register being read or written + // + uvm_reg_item rw_info; + + // Variable -- NODOCS -- sequencer + // + // Sequencer executing the operation + // + uvm_sequencer_base sequencer; + + + // @uvm-ieee 1800.2-2017 auto 19.4.2.3 + function new(string name=""); + super.new(name); + endfunction + + string fname; + int lineno; + +endclass: uvm_reg_frontdoor diff --git a/test_regress/t/t_uvm/reg/uvm_vreg.svh b/test_regress/t/t_uvm/reg/uvm_vreg.svh new file mode 100644 index 0000000000..96a8e64d66 --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_vreg.svh @@ -0,0 +1,1227 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Virtual Registers +//------------------------------------------------------------------------------ +// +// A virtual register is a collection of fields, +// overlaid on top of a memory, usually in an array. +// The semantics and layout of virtual registers comes from +// an agreement between the software and the hardware, +// not any physical structures in the DUT. +// +//------------------------------------------------------------------------------ + +typedef class uvm_mem_region; +typedef class uvm_mem_mam; + +typedef class uvm_vreg_cbs; + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_vreg +// +// Virtual register abstraction base class +// +// A virtual register represents a set of fields that are +// logically implemented in consecutive memory locations. +// +// All virtual register accesses eventually turn into memory accesses. +// +// A virtual register array may be implemented on top of +// any memory abstraction class and possibly dynamically +// resized and/or relocated. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.9.1 +class uvm_vreg extends uvm_object; + + `uvm_register_cb(uvm_vreg, uvm_vreg_cbs) + + local bit locked; + local uvm_reg_block parent; + local int unsigned n_bits; + local int unsigned n_used_bits; + + local uvm_vreg_field fields[$]; // Fields in LSB to MSB order + + local uvm_mem mem; // Where is it implemented? + local uvm_reg_addr_t offset; // Start of vreg[0] + local int unsigned incr; // From start to start of next + local longint unsigned size; //number of vregs + local bit is_static; + + local uvm_mem_region region; // Not NULL if implemented via MAM + + local semaphore atomic; // Field RMW operations must be atomic + local string fname; + local int lineno; + local bit read_in_progress; + local bit write_in_progress; + + // + // Group -- NODOCS -- Initialization + // + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.1.1 + extern function new(string name, + int unsigned n_bits); + + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.1.2 + extern function void configure(uvm_reg_block parent, + uvm_mem mem = null, + longint unsigned size = 0, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.1.3 + extern virtual function bit implement(longint unsigned n, + uvm_mem mem = null, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.1.4 + extern virtual function uvm_mem_region allocate(longint unsigned n, + uvm_mem_mam mam, + uvm_mem_mam_policy alloc = null); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.1.5 + extern virtual function uvm_mem_region get_region(); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.1.6 + extern virtual function void release_region(); + + + /*local*/ extern virtual function void set_parent(uvm_reg_block parent); + /*local*/ extern function void Xlock_modelX(); + + /*local*/ extern function void add_field(uvm_vreg_field field); + /*local*/ extern task XatomicX(bit on); + + // + // Group -- NODOCS -- Introspection + // + + // + // Function -- NODOCS -- get_name + // Get the simple name + // + // Return the simple object name of this register. + // + + // + // Function -- NODOCS -- get_full_name + // Get the hierarchical name + // + // Return the hierarchal name of this register. + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.1 + extern virtual function uvm_reg_block get_parent(); + extern virtual function uvm_reg_block get_block(); + + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.2 + extern virtual function uvm_mem get_memory(); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.3 + extern virtual function int get_n_maps (); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.4 + extern function bit is_in_map (uvm_reg_map map); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.5 + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.6 + extern virtual function string get_rights(uvm_reg_map map = null); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.7 + extern virtual function string get_access(uvm_reg_map map = null); + + // + // FUNCTION -- NODOCS -- get_size + // Returns the size of the virtual register array. + // + extern virtual function int unsigned get_size(); + + // + // FUNCTION -- NODOCS -- get_n_bytes + // Returns the width, in bytes, of a virtual register. + // + // The width of a virtual register is always a multiple of the width + // of the memory locations used to implement it. + // For example, a virtual register containing two 1-byte fields + // implemented in a memory with 4-bytes memory locations is 4-byte wide. + // + extern virtual function int unsigned get_n_bytes(); + + // + // FUNCTION -- NODOCS -- get_n_memlocs + // Returns the number of memory locations used + // by a single virtual register. + // + extern virtual function int unsigned get_n_memlocs(); + + // + // FUNCTION -- NODOCS -- get_incr + // Returns the number of memory locations + // between two individual virtual registers in the same array. + // + extern virtual function int unsigned get_incr(); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.12 + extern virtual function void get_fields(ref uvm_vreg_field fields[$]); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.13 + extern virtual function uvm_vreg_field get_field_by_name(string name); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.14 + extern virtual function uvm_reg_addr_t get_offset_in_memory(longint unsigned idx); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.2.15 + extern virtual function uvm_reg_addr_t get_address(longint unsigned idx, + uvm_reg_map map = null); + + // + // Group -- NODOCS -- HDL Access + // + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.3.1 + extern virtual task write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.3.2 + extern virtual task read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.3.3 + extern virtual task poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.3.4 + extern virtual task peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.3.5 + extern function void reset(string kind = "HARD"); + + + // + // Group -- NODOCS -- Callbacks + // + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.4.1 + virtual task pre_write(longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.4.2 + virtual task post_write(longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.4.3 + virtual task pre_read(longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + + + // @uvm-ieee 1800.2-2017 auto 18.9.1.4.4 + virtual task post_read(longint unsigned idx, + ref uvm_reg_data_t rdat, + input uvm_door_e path, + input uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read + + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + +endclass: uvm_vreg + + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_vreg_cbs +// +// Pre/post read/write callback facade class +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.9.2.1 +virtual class uvm_vreg_cbs extends uvm_callback; + + `uvm_object_abstract_utils(uvm_vreg_cbs) + + string fname; + int lineno; + + function new(string name = "uvm_reg_cbs"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.9.2.2.1 + virtual task pre_write(uvm_vreg rg, + longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + + + + // @uvm-ieee 1800.2-2017 auto 18.9.2.2.2 + virtual task post_write(uvm_vreg rg, + longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + + + + // @uvm-ieee 1800.2-2017 auto 18.9.2.2.3 + virtual task pre_read(uvm_vreg rg, + longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + + + + // @uvm-ieee 1800.2-2017 auto 18.9.2.2.4 + virtual task post_read(uvm_vreg rg, + longint unsigned idx, + ref uvm_reg_data_t rdat, + input uvm_door_e path, + input uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read +endclass: uvm_vreg_cbs + + +// +// Type -- NODOCS -- uvm_vreg_cb +// Convenience callback type declaration +// +// Use this declaration to register virtual register callbacks rather than +// the more verbose parameterized class +// +typedef uvm_callbacks#(uvm_vreg, uvm_vreg_cbs) uvm_vreg_cb /* @uvm-ieee 1800.2-2017 auto D.4.6.9*/ ; + +// +// Type -- NODOCS -- uvm_vreg_cb_iter +// Convenience callback iterator type declaration +// +// Use this declaration to iterate over registered virtual register callbacks +// rather than the more verbose parameterized class +// +typedef uvm_callback_iter#(uvm_vreg, uvm_vreg_cbs) uvm_vreg_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.6.10*/ ; + + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +function uvm_vreg::new(string name, + int unsigned n_bits); + super.new(name); + + if (n_bits == 0) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" cannot have 0 bits", this.get_full_name())) + n_bits = 1; + end + if (n_bits > `UVM_REG_DATA_WIDTH) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" cannot have more than %0d bits (%0d)", this.get_full_name(), `UVM_REG_DATA_WIDTH, n_bits)) + n_bits = `UVM_REG_DATA_WIDTH; + end + this.n_bits = n_bits; + + this.locked = 0; +endfunction: new + +function void uvm_vreg::configure(uvm_reg_block parent, + uvm_mem mem = null, + longint unsigned size = 0, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + this.parent = parent; + + this.n_used_bits = 0; + + if (mem != null) begin + void'(this.implement(size, mem, offset, incr)); + this.is_static = 1; + end + else begin + this.mem = null; + this.is_static = 0; + end + this.parent.add_vreg(this); + + this.atomic = new(1); +endfunction: configure + + + +function void uvm_vreg::Xlock_modelX(); + if (this.locked) return; + + this.locked = 1; +endfunction: Xlock_modelX + + +function void uvm_vreg::add_field(uvm_vreg_field field); + int offset; + int idx; + + if (this.locked) begin + `uvm_error("RegModel", "Cannot add virtual field to locked virtual register model") + return; + end + + if (field == null) `uvm_fatal("RegModel", "Attempting to register NULL virtual field") + + // Store fields in LSB to MSB order + offset = field.get_lsb_pos_in_register(); + + idx = -1; + foreach (this.fields[i]) begin + if (offset < this.fields[i].get_lsb_pos_in_register()) begin + int j = i; + this.fields.insert(j, field); + idx = i; + break; + end + end + if (idx < 0) begin + this.fields.push_back(field); + idx = this.fields.size()-1; + end + + this.n_used_bits += field.get_n_bits(); + + // Check if there are too many fields in the register + if (this.n_used_bits > this.n_bits) begin + `uvm_error("RegModel", $sformatf("Virtual fields use more bits (%0d) than available in virtual register \"%s\" (%0d)", + this.n_used_bits, this.get_full_name(), this.n_bits)) + end + + // Check if there are overlapping fields + if (idx > 0) begin + if (this.fields[idx-1].get_lsb_pos_in_register() + + this.fields[idx-1].get_n_bits() > offset) begin + `uvm_error("RegModel", $sformatf("Field %s overlaps field %s in virtual register \"%s\"", + this.fields[idx-1].get_name(), + field.get_name(), + this.get_full_name())) + end + end + if (idx < this.fields.size()-1) begin + if (offset + field.get_n_bits() > + this.fields[idx+1].get_lsb_pos_in_register()) begin + `uvm_error("RegModel", $sformatf("Field %s overlaps field %s in virtual register \"%s\"", + field.get_name(), + this.fields[idx+1].get_name(), + this.get_full_name())) + end + end +endfunction: add_field + + +task uvm_vreg::XatomicX(bit on); + if (on) this.atomic.get(1); + else begin + // Maybe a key was put back in by a spurious call to reset() + void'(this.atomic.try_get(1)); + this.atomic.put(1); + end +endtask: XatomicX + + +function void uvm_vreg::reset(string kind = "HARD"); + // Put back a key in the semaphore if it is checked out + // in case a thread was killed during an operation + void'(this.atomic.try_get(1)); + this.atomic.put(1); +endfunction: reset + + +function string uvm_vreg::get_full_name(); + uvm_reg_block blk; + + get_full_name = this.get_name(); + + // Do not include top-level name in full name + blk = this.get_block(); + if (blk == null) return get_full_name; + if (blk.get_parent() == null) return get_full_name; + + get_full_name = {this.parent.get_full_name(), ".", get_full_name}; +endfunction: get_full_name + +function void uvm_vreg::set_parent(uvm_reg_block parent); + this.parent = parent; +endfunction: set_parent + +function uvm_reg_block uvm_vreg::get_parent(); + get_parent = this.parent; +endfunction: get_parent + +function uvm_reg_block uvm_vreg::get_block(); + get_block = this.parent; +endfunction: get_block + + +function bit uvm_vreg::implement(longint unsigned n, + uvm_mem mem = null, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + + uvm_mem_region region; + + if(n < 1) + begin + `uvm_error("RegModel", $sformatf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_full_name())) + return 0; + end + + if (mem == null) begin + `uvm_error("RegModel", $sformatf("Attempting to implement virtual register \"%s\" using a NULL uvm_mem reference", this.get_full_name())) + return 0; + end + + if (this.is_static) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically implemented", this.get_full_name())) + return 0; + end + + if (mem.get_block() != this.parent) begin + `uvm_error("RegModel", $sformatf("Attempting to implement virtual register \"%s\" on memory \"%s\" in a different block", + this.get_full_name(), + mem.get_full_name())) + return 0; + end + + begin + int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; + if (incr == 0) incr = min_incr; + if (min_incr > incr) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", + this.get_full_name(), incr, + min_incr, mem.get_full_name())) + return 0; + end + end + + // Is the memory big enough for ya? + if (offset + (n * incr) > mem.get_size()) begin + `uvm_error("RegModel", $sformatf("Given Offset for Virtual register \"%s[%0d]\" is too big for memory %s@'h%0h", this.get_full_name(), n, mem.get_full_name(), offset)) + return 0; + end + + region = mem.mam.reserve_region(offset,n*incr*mem.get_n_bytes()); + + if (region == null) begin + `uvm_error("RegModel", $sformatf("Could not allocate a memory region for virtual register \"%s\"", this.get_full_name())) + return 0; + end + + if (this.mem != null) begin + `uvm_info("RegModel", $sformatf("Virtual register \"%s\" is being moved re-implemented from %s@'h%0h to %s@'h%0h", + this.get_full_name(), + this.mem.get_full_name(), + this.offset, + mem.get_full_name(), offset),UVM_MEDIUM) + this.release_region(); + end + + this.region = region; + this.mem = mem; + this.size = n; + this.offset = offset; + this.incr = incr; + this.mem.Xadd_vregX(this); + + return 1; +endfunction: implement + + +function uvm_mem_region uvm_vreg::allocate(longint unsigned n, + uvm_mem_mam mam, + uvm_mem_mam_policy alloc=null); + + uvm_mem mem; + + if(n < 1) + begin + `uvm_error("RegModel", $sformatf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_full_name())) + return null; + end + + if (mam == null) begin + `uvm_error("RegModel", $sformatf("Attempting to implement virtual register \"%s\" using a NULL uvm_mem_mam reference", this.get_full_name())) + return null; + end + + if (this.is_static) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically allocated", this.get_full_name())) + return null; + end + + mem = mam.get_memory(); + if (mem.get_block() != this.parent) begin + `uvm_error("RegModel", $sformatf("Attempting to allocate virtual register \"%s\" on memory \"%s\" in a different block", + this.get_full_name(), + mem.get_full_name())) + return null; + end + + begin + int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; + if (incr == 0) incr = min_incr; + if (min_incr < incr) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", + this.get_full_name(), incr, + min_incr, mem.get_full_name())) + return null; + end + end + + // Need memory at least of size num_vregs*sizeof(vreg) in bytes. + allocate = mam.request_region(n*incr*mem.get_n_bytes(), alloc); + if (allocate == null) begin + `uvm_error("RegModel", $sformatf("Could not allocate a memory region for virtual register \"%s\"", this.get_full_name())) + return null; + end + + if (this.mem != null) begin + `uvm_info("RegModel", $sformatf("Virtual register \"%s\" is being moved from %s@'h%0h to %s@'h%0h", + this.get_full_name(), + this.mem.get_full_name(), + this.offset, + mem.get_full_name(), + allocate.get_start_offset()),UVM_MEDIUM) + + this.release_region(); + end + + this.region = allocate; + + this.mem = mam.get_memory(); + this.offset = allocate.get_start_offset(); + this.size = n; + this.incr = incr; + + this.mem.Xadd_vregX(this); +endfunction: allocate + + +function uvm_mem_region uvm_vreg::get_region(); + return this.region; +endfunction: get_region + + +function void uvm_vreg::release_region(); + if (this.is_static) begin + `uvm_error("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically released", this.get_full_name())) + return; + end + + if (this.mem != null) + this.mem.Xdelete_vregX(this); + + if (this.region != null) begin + this.region.release_region(); + end + + this.region = null; + this.mem = null; + this.size = 0; + this.offset = 0; + + this.reset(); +endfunction: release_region + + +function uvm_mem uvm_vreg::get_memory(); + return this.mem; +endfunction: get_memory + + +function uvm_reg_addr_t uvm_vreg::get_offset_in_memory(longint unsigned idx); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_offset_in_memory() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return 0; + end + + return this.offset + idx * this.incr; +endfunction + + +function uvm_reg_addr_t uvm_vreg::get_address(longint unsigned idx, + uvm_reg_map map = null); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot get address of of unimplemented virtual register \"%s\".", this.get_full_name())) + return 0; + end + + return this.mem.get_address(this.get_offset_in_memory(idx), map); +endfunction: get_address + + +function int unsigned uvm_vreg::get_size(); + if (this.size == 0) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_size() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return 0; + end + + return this.size; +endfunction: get_size + + +function int unsigned uvm_vreg::get_n_bytes(); + return ((this.n_bits-1) / 8) + 1; +endfunction: get_n_bytes + + +function int unsigned uvm_vreg::get_n_memlocs(); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_n_memlocs() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return 0; + end + + return (this.get_n_bytes()-1) / this.mem.get_n_bytes() + 1; +endfunction: get_n_memlocs + + +function int unsigned uvm_vreg::get_incr(); + if (this.incr == 0) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_incr() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return 0; + end + + return this.incr; +endfunction: get_incr + + +function int uvm_vreg::get_n_maps(); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_n_maps() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return 0; + end + + return this.mem.get_n_maps(); +endfunction: get_n_maps + + +function void uvm_vreg::get_maps(ref uvm_reg_map maps[$]); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_maps() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return; + end + + this.mem.get_maps(maps); +endfunction: get_maps + + +function bit uvm_vreg::is_in_map(uvm_reg_map map); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::is_in_map() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return 0; + end + + return this.mem.is_in_map(map); +endfunction + + +function string uvm_vreg::get_access(uvm_reg_map map = null); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_rights() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return "RW"; + end + + return this.mem.get_access(map); +endfunction: get_access + + +function string uvm_vreg::get_rights(uvm_reg_map map = null); + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg::get_rights() on unimplemented virtual register \"%s\"", + this.get_full_name())) + return "RW"; + end + + return this.mem.get_rights(map); +endfunction: get_rights + + +function void uvm_vreg::get_fields(ref uvm_vreg_field fields[$]); + foreach(this.fields[i]) + fields.push_back(this.fields[i]); +endfunction: get_fields + + +function uvm_vreg_field uvm_vreg::get_field_by_name(string name); + foreach (this.fields[i]) begin + if (this.fields[i].get_name() == name) begin + return this.fields[i]; + end + end + `uvm_warning("RegModel", $sformatf("Unable to locate field \"%s\" in virtual register \"%s\".", + name, this.get_full_name())) + get_field_by_name = null; +endfunction: get_field_by_name + + +task uvm_vreg::write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_vreg_cb_iter cbs = new(this); + + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + + this.write_in_progress = 1'b1; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot write to unimplemented virtual register \"%s\".", this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + if (path == UVM_DEFAULT_DOOR) + path = this.parent.get_default_door(); + + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + + f.pre_write(idx, tmp, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_write(f, idx, tmp, path, map); + end + + value = (value & ~msk) | (tmp << lsb); + end + this.pre_write(idx, value, path, map); + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_write(this, idx, value, path, map); + end + + addr = this.offset + (idx * this.incr); + + lsb = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + + msk = ((1<<(this.mem.get_n_bytes()*8))-1) << lsb; + tmp = (value & msk) >> lsb; + this.mem.write(s, addr + i, tmp, path, map , parent, , extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + lsb += this.mem.get_n_bytes() * 8; + end + + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(this, idx, value, path, map, status); + end + this.post_write(idx, value, path, map, status); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(f, idx, tmp, path, map, status); + end + f.post_write(idx, tmp, path, map, status); + + value = (value & ~msk) | (tmp << lsb); + end + + `uvm_info("RegModel", $sformatf("Wrote virtual register \"%s\"[%0d] via %s with: 'h%h", + this.get_full_name(), idx, + (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", + value),UVM_MEDIUM) + + this.write_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; + +endtask: write + + +task uvm_vreg::read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_vreg_cb_iter cbs = new(this); + + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.read_in_progress = 1'b1; + this.fname = fname; + this.lineno = lineno; + + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot read from unimplemented virtual register \"%s\".", this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + if (path == UVM_DEFAULT_DOOR) + path = this.parent.get_default_door(); + + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + + f.pre_read(idx, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(f, idx, path, map); + end + end + this.pre_read(idx, path, map); + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(this, idx, path, map); + end + + addr = this.offset + (idx * this.incr); + + lsb = 0; + value = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + + this.mem.read(s, addr + i, tmp, path, map, parent, , extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + + value |= tmp << lsb; + lsb += this.mem.get_n_bytes() * 8; + end + + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_read(this, idx, value, path, map, status); + end + this.post_read(idx, value, path, map, status); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + + lsb = f.get_lsb_pos_in_register(); + + msk = ((1<> lsb; + + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_read(f, idx, tmp, path, map, status); + end + f.post_read(idx, tmp, path, map, status); + + value = (value & ~msk) | (tmp << lsb); + end + + `uvm_info("RegModel", $sformatf("Read virtual register \"%s\"[%0d] via %s: 'h%h", + this.get_full_name(), idx, + (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", + value),UVM_MEDIUM) + + this.read_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: read + + +task uvm_vreg::poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.fname = fname; + this.lineno = lineno; + + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot poke in unimplemented virtual register \"%s\".", this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + addr = this.offset + (idx * this.incr); + + lsb = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + + msk = ((1<<(this.mem.get_n_bytes() * 8))-1) << lsb; + tmp = (value & msk) >> lsb; + + this.mem.poke(status, addr + i, tmp, "", parent, extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + + lsb += this.mem.get_n_bytes() * 8; + end + + `uvm_info("RegModel", $sformatf("Poked virtual register \"%s\"[%0d] with: 'h%h", + this.get_full_name(), idx, value),UVM_MEDIUM) + this.fname = ""; + this.lineno = 0; + +endtask: poke + + +task uvm_vreg::peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.fname = fname; + this.lineno = lineno; + + if (this.mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot peek in from unimplemented virtual register \"%s\".", this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + addr = this.offset + (idx * this.incr); + + lsb = 0; + value = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + + this.mem.peek(status, addr + i, tmp, "", parent, extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + + value |= tmp << lsb; + lsb += this.mem.get_n_bytes() * 8; + end + + `uvm_info("RegModel", $sformatf("Peeked virtual register \"%s\"[%0d]: 'h%h", + this.get_full_name(), idx, value),UVM_MEDIUM) + + this.fname = ""; + this.lineno = 0; + +endtask: peek + + +function void uvm_vreg::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_generic("initiator", parent.get_type_name(), -1, convert2string()); +endfunction + +function string uvm_vreg::convert2string(); + string res_str; + string t_str; + bit with_debug_info; + $sformat(convert2string, "Virtual register %s -- ", + this.get_full_name()); + + if (this.size == 0) + $sformat(convert2string, "%sunimplemented", convert2string); + else begin + uvm_reg_map maps[$]; + mem.get_maps(maps); + + $sformat(convert2string, "%s[%0d] in %0s['h%0h+'h%0h]\n", convert2string, + this.size, this.mem.get_full_name(), this.offset, this.incr); + foreach (maps[i]) begin + uvm_reg_addr_t addr0 = this.get_address(0, maps[i]); + + $sformat(convert2string, " Address in map '%s' -- @'h%0h+%0h", + maps[i].get_full_name(), addr0, this.get_address(1, maps[i]) - addr0); + end + end + foreach(this.fields[i]) begin + $sformat(convert2string, "%s\n%s", convert2string, + this.fields[i].convert2string()); + end + +endfunction: convert2string + + + +//TODO - add fatal messages +function uvm_object uvm_vreg::clone(); + return null; +endfunction + +function void uvm_vreg::do_copy (uvm_object rhs); +endfunction + +function bit uvm_vreg::do_compare (uvm_object rhs, + uvm_comparer comparer); + return 0; +endfunction + +function void uvm_vreg::do_pack (uvm_packer packer); +endfunction + +function void uvm_vreg::do_unpack (uvm_packer packer); +endfunction diff --git a/test_regress/t/t_uvm/reg/uvm_vreg_field.svh b/test_regress/t/t_uvm/reg/uvm_vreg_field.svh new file mode 100644 index 0000000000..26d130a29f --- /dev/null +++ b/test_regress/t/t_uvm/reg/uvm_vreg_field.svh @@ -0,0 +1,826 @@ +// +// ------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2004-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2014-2018 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. +// ------------------------------------------------------------- +// + + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Virtual Register Field Classes +// +// This section defines the virtual field and callback classes. +// +// A virtual field is set of contiguous bits in one or more memory locations. +// The semantics and layout of virtual fields comes from +// an agreement between the software and the hardware, +// not any physical structures in the DUT. +// +//------------------------------------------------------------------------------ + +typedef class uvm_vreg_field_cbs; + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_vreg_field +// +// Virtual field abstraction class +// +// A virtual field represents a set of adjacent bits that are +// logically implemented in consecutive memory locations. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.10.1 +class uvm_vreg_field extends uvm_object; + + `uvm_object_utils(uvm_vreg_field) + `uvm_register_cb(uvm_vreg_field, uvm_vreg_field_cbs) + + local uvm_vreg parent; + local int unsigned lsb; + local int unsigned size; + local string fname; + local int lineno; + local bit read_in_progress; + local bit write_in_progress; + + + // + // Group -- NODOCS -- initialization + // + + + // @uvm-ieee 1800.2-2017 auto 18.10.2.1 + extern function new(string name = "uvm_vreg_field"); + + + // @uvm-ieee 1800.2-2017 auto 18.10.2.2 + extern function void configure(uvm_vreg parent, + int unsigned size, + int unsigned lsb_pos); + + + // + // Group -- NODOCS -- Introspection + // + + // + // Function -- NODOCS -- get_name + // Get the simple name + // + // Return the simple object name of this virtual field + // + + // + // Function -- NODOCS -- get_full_name + // Get the hierarchical name + // + // Return the hierarchal name of this virtual field + // The base of the hierarchical name is the root block. + // + extern virtual function string get_full_name(); + + + // @uvm-ieee 1800.2-2017 auto 18.10.3.1 + extern virtual function uvm_vreg get_parent(); + extern virtual function uvm_vreg get_register(); + + // + // FUNCTION -- NODOCS -- get_lsb_pos_in_register + // Return the position of the virtual field + /// + // Returns the index of the least significant bit of the virtual field + // in the virtual register that instantiates it. + // An offset of 0 indicates a field that is aligned with the + // least-significant bit of the register. + // + extern virtual function int unsigned get_lsb_pos_in_register(); + + // + // FUNCTION -- NODOCS -- get_n_bits + // Returns the width, in bits, of the virtual field. + // + extern virtual function int unsigned get_n_bits(); + + + // @uvm-ieee 1800.2-2017 auto 18.10.3.4 + extern virtual function string get_access(uvm_reg_map map = null); + + + // + // Group -- NODOCS -- HDL Access + // + + + // @uvm-ieee 1800.2-2017 auto 18.10.4.1 + extern virtual task write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.10.4.2 + extern virtual task read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + + // @uvm-ieee 1800.2-2017 auto 18.10.4.3 + extern virtual task poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + + // @uvm-ieee 1800.2-2017 auto 18.10.4.4 + extern virtual task peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + + // + // Group -- NODOCS -- Callbacks + // + + + + // @uvm-ieee 1800.2-2017 auto 18.10.5.1 + virtual task pre_write(longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + + + // @uvm-ieee 1800.2-2017 auto 18.10.5.2 + virtual task post_write(longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + + + // @uvm-ieee 1800.2-2017 auto 18.10.5.3 + virtual task pre_read(longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + + + // @uvm-ieee 1800.2-2017 auto 18.10.5.4 + virtual task post_read(longint unsigned idx, + ref uvm_reg_data_t rdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read + + + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); + +endclass: uvm_vreg_field + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_vreg_field_cbs +// +// Pre/post read/write callback facade class +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.10.6.1 +virtual class uvm_vreg_field_cbs extends uvm_callback; + string fname; + int lineno; + + + `uvm_object_abstract_utils(uvm_vreg_field_cbs) + + function new(string name = "uvm_vreg_field_cbs"); + super.new(name); + endfunction + + + + // @uvm-ieee 1800.2-2017 auto 18.10.6.2.1 + virtual task pre_write(uvm_vreg_field field, + longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + + + + // @uvm-ieee 1800.2-2017 auto 18.10.6.2.2 + virtual task post_write(uvm_vreg_field field, + longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + + + + // @uvm-ieee 1800.2-2017 auto 18.10.6.2.3 + virtual task pre_read(uvm_vreg_field field, + longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + + + + // @uvm-ieee 1800.2-2017 auto 18.10.6.2.4 + virtual task post_read(uvm_vreg_field field, + longint unsigned idx, + ref uvm_reg_data_t rdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read +endclass: uvm_vreg_field_cbs + + +// +// Type -- NODOCS -- uvm_vreg_field_cb +// Convenience callback type declaration +// +// Use this declaration to register virtual field callbacks rather than +// the more verbose parameterized class +// +typedef uvm_callbacks#(uvm_vreg_field, uvm_vreg_field_cbs) uvm_vreg_field_cb /* @uvm-ieee 1800.2-2017 auto D.4.6.11*/ ; + +// +// Type -- NODOCS -- uvm_vreg_field_cb_iter +// Convenience callback iterator type declaration +// +// Use this declaration to iterate over registered virtual field callbacks +// rather than the more verbose parameterized class +// +typedef uvm_callback_iter#(uvm_vreg_field, uvm_vreg_field_cbs) uvm_vreg_field_cb_iter /* @uvm-ieee 1800.2-2017 auto D.4.6.12*/ ; + + + + +function uvm_vreg_field::new(string name="uvm_vreg_field"); + super.new(name); +endfunction: new + +function void uvm_vreg_field::configure(uvm_vreg parent, + int unsigned size, + int unsigned lsb_pos); + this.parent = parent; + if (size == 0) begin + `uvm_error("RegModel", $sformatf("Virtual field \"%s\" cannot have 0 bits", this.get_full_name())) + size = 1; + end + if (size > `UVM_REG_DATA_WIDTH) begin + `uvm_error("RegModel", $sformatf("Virtual field \"%s\" cannot have more than %0d bits", + this.get_full_name(), + `UVM_REG_DATA_WIDTH)) + size = `UVM_REG_DATA_WIDTH; + end + + this.size = size; + this.lsb = lsb_pos; + + this.parent.add_field(this); +endfunction: configure + + + +function string uvm_vreg_field::get_full_name(); + get_full_name = {this.parent.get_full_name(), ".", this.get_name()}; +endfunction: get_full_name + + +function uvm_vreg uvm_vreg_field::get_register(); + get_register = this.parent; +endfunction: get_register + + +function uvm_vreg uvm_vreg_field::get_parent(); + get_parent = this.parent; +endfunction: get_parent + + + +function int unsigned uvm_vreg_field::get_lsb_pos_in_register(); + get_lsb_pos_in_register = this.lsb; +endfunction: get_lsb_pos_in_register + + +function int unsigned uvm_vreg_field::get_n_bits(); + get_n_bits = this.size; +endfunction: get_n_bits + + +function string uvm_vreg_field::get_access(uvm_reg_map map = null); + if (this.parent.get_memory() == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::get_rights() on unimplemented virtual field \"%s\"", + this.get_full_name())) + return "RW"; + end + + return this.parent.get_access(map); +endfunction: get_access + + +task uvm_vreg_field::write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + + int flsb, fmsb, rmwbits; + int segsiz, segn; + uvm_mem mem; + uvm_door_e rm_path; + + uvm_vreg_field_cb_iter cbs = new(this); + + this.fname = fname; + this.lineno = lineno; + + write_in_progress = 1'b1; + mem = this.parent.get_memory(); + if (mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::write() on unimplemented virtual register \"%s\"", + this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = this.parent.get_block(); + path = blk.get_default_door(); + end + + status = UVM_IS_OK; + + this.parent.XatomicX(1); + + if (value >> this.size) begin + `uvm_warning("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits())) + value &= value & ((1< 0) begin + uvm_reg_addr_t segn; + + mem.read(st, segoff, tmp, rm_path, map, parent, , extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + `uvm_error("RegModel", + $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", + mem.get_full_name(), segoff, this.get_full_name())) + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + + value = (value << rmwbits) | (tmp & ((1< 0) begin + if (segn > 0) begin + mem.read(st, segoff + segn - 1, tmp, rm_path, map, parent,, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + `uvm_error("RegModel", + $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", + mem.get_full_name(), segoff+segn-1, + this.get_full_name())) + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + end + value |= (tmp & ~((1<> segsiz; + end + + this.post_write(idx, value, path, map, status); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(this, idx, value, path, map, status); + end + + this.parent.XatomicX(0); + + + `uvm_info("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h", + this.get_full_name(), idx, + (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", + value),UVM_MEDIUM) + + write_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: write + + +task uvm_vreg_field::read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + + int flsb, lsb; + int segsiz, segn; + uvm_mem mem; + + uvm_vreg_field_cb_iter cbs = new(this); + + this.fname = fname; + this.lineno = lineno; + + read_in_progress = 1'b1; + mem = this.parent.get_memory(); + if (mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::read() on unimplemented virtual register \"%s\"", + this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = this.parent.get_block(); + path = blk.get_default_door(); + end + + status = UVM_IS_OK; + + this.parent.XatomicX(1); + + value = 0; + + this.pre_read(idx, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(this, idx, path, map); + end + + segsiz = mem.get_n_bytes() * 8; + flsb = this.get_lsb_pos_in_register(); + segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); + lsb = flsb % segsiz; + + // Total number of memory segment in this field + segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; + + // Read each of the segments, MSB first + segoff += segn - 1; + repeat (segn) begin + value = value << segsiz; + + mem.read(st, segoff, tmp, path, map, parent, , extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; + + segoff--; + value |= tmp; + end + + // Any bits on the LSB side we need to get rid of? + value = value >> lsb; + + // Any bits on the MSB side we need to get rid of? + value &= (1<> this.size) begin + `uvm_warning("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits())) + value &= value & ((1< 0) begin + uvm_reg_addr_t segn; + + mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + `uvm_error("RegModel", + $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", + mem.get_full_name(), segoff, this.get_full_name())) + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + + value = (value << rmwbits) | (tmp & ((1< 0) begin + if (segn > 0) begin + mem.peek(st, segoff + segn - 1, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + `uvm_error("RegModel", + $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", + mem.get_full_name(), segoff+segn-1, + this.get_full_name())) + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + end + value |= (tmp & ~((1<> segsiz; + end + + this.parent.XatomicX(0); + + `uvm_info("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] with: 'h%h", + this.get_full_name(), idx, value),UVM_MEDIUM) + + this.fname = ""; + this.lineno = 0; +endtask: poke + + +task uvm_vreg_field::peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + + int flsb, lsb; + int segsiz, segn; + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + + mem = this.parent.get_memory(); + if (mem == null) begin + `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::peek() on unimplemented virtual register \"%s\"", + this.get_full_name())) + status = UVM_NOT_OK; + return; + end + + status = UVM_IS_OK; + + this.parent.XatomicX(1); + + value = 0; + + segsiz = mem.get_n_bytes() * 8; + flsb = this.get_lsb_pos_in_register(); + segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); + lsb = flsb % segsiz; + + // Total number of memory segment in this field + segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; + + // Read each of the segments, MSB first + segoff += segn - 1; + repeat (segn) begin + value = value << segsiz; + + mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); + + if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; + + segoff--; + value |= tmp; + end + + // Any bits on the LSB side we need to get rid of? + value = value >> lsb; + + // Any bits on the MSB side we need to get rid of? + value &= (1< using req_port.put(item). Typically, the req_port would be + // connected to the req_export on an instance of a + // , which would be responsible for + // executing the item. + // + task run_phase(uvm_phase phase); + REQ t; + int selected_sequence; + + fork + super.run_phase(phase); + forever + begin + m_select_sequence(); + m_req_fifo.get(t); + req_port.put(t); + m_wait_for_item_sequence_id = t.get_sequence_id(); + m_wait_for_item_transaction_id = t.get_transaction_id(); + end + join + endtask + + protected virtual function int m_find_number_driver_connections(); + return req_port.size(); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/seq/uvm_seq.svh b/test_regress/t/t_uvm/seq/uvm_seq.svh new file mode 100644 index 0000000000..19e49ea44f --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_seq.svh @@ -0,0 +1,38 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2017 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. +//------------------------------------------------------------------------------ + +`include "seq/uvm_sequence_item.svh" +`include "seq/uvm_sequencer_base.svh" +`include "seq/uvm_sequencer_analysis_fifo.svh" +`include "seq/uvm_sequencer_param_base.svh" +`include "seq/uvm_sequencer.svh" +`include "seq/uvm_push_sequencer.svh" +`include "seq/uvm_sequence_base.svh" +`include "seq/uvm_sequence.svh" +`include "seq/uvm_sequence_library.svh" + +typedef uvm_sequence #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequence_type; +typedef uvm_sequencer #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequencer_type; +typedef uvm_driver #(uvm_sequence_item, uvm_sequence_item) uvm_default_driver_type; +typedef uvm_sequencer_param_base #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequencer_param_type; diff --git a/test_regress/t/t_uvm/seq/uvm_sequence.svh b/test_regress/t/t_uvm/seq/uvm_sequence.svh new file mode 100644 index 0000000000..a2e6573f32 --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequence.svh @@ -0,0 +1,154 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2014-2015 NVIDIA Corporation +// Copyright 2013 Cisco Systems, 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_sequence #(REQ,RSP) +// +// The uvm_sequence class provides the interfaces necessary in order to create +// streams of sequence items and/or other sequences. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 14.3.1 +virtual class uvm_sequence #(type REQ = uvm_sequence_item, + type RSP = REQ) extends uvm_sequence_base; + + typedef uvm_sequencer_param_base #(REQ, RSP) sequencer_t; + + sequencer_t param_sequencer; + + // Variable -- NODOCS -- req + // + // The sequence contains a field of the request type called req. The user + // can use this field, if desired, or create another field to use. The + // default ~do_print~ will print this field. + REQ req; + + // Variable -- NODOCS -- rsp + // + // The sequence contains a field of the response type called rsp. The user + // can use this field, if desired, or create another field to use. The + // default ~do_print~ will print this field. + RSP rsp; + + // Function -- NODOCS -- new + // + // Creates and initializes a new sequence object. + + // @uvm-ieee 1800.2-2017 auto 14.3.3.1 + function new (string name = "uvm_sequence"); + super.new(name); + endfunction + + // Function -- NODOCS -- send_request + // + // This method will send the request item to the sequencer, which will forward + // it to the driver. If the rerandomize bit is set, the item will be + // randomized before being sent to the driver. The send_request function may + // only be called after returns. + + function void send_request(uvm_sequence_item request, bit rerandomize = 0); + REQ m_request; + + if (m_sequencer == null) begin + uvm_report_fatal("SSENDREQ", "Null m_sequencer reference", UVM_NONE); + end + if (!$cast(m_request, request)) begin + uvm_report_fatal("SSENDREQ", "Failure to cast uvm_sequence_item to request", UVM_NONE); + end + m_sequencer.send_request(this, m_request, rerandomize); + endfunction + + + // Function -- NODOCS -- get_current_item + // + // Returns the request item currently being executed by the sequencer. If the + // sequencer is not currently executing an item, this method will return ~null~. + // + // The sequencer is executing an item from the time that get_next_item or peek + // is called until the time that get or item_done is called. + // + // Note that a driver that only calls get will never show a current item, + // since the item is completed at the same time as it is requested. + + // @uvm-ieee 1800.2-2017 auto 14.3.3.2 + function REQ get_current_item(); + if (!$cast(param_sequencer, m_sequencer)) + uvm_report_fatal("SGTCURR", "Failure to cast m_sequencer to the parameterized sequencer", UVM_NONE); + return (param_sequencer.get_current_item()); + endfunction + + + // Task -- NODOCS -- get_response + // + // By default, sequences must retrieve responses by calling get_response. + // If no transaction_id is specified, this task will return the next response + // sent to this sequence. If no response is available in the response queue, + // the method will block until a response is received. + // + // If a transaction_id is parameter is specified, the task will block until + // a response with that transaction_id is received in the response queue. + // + // The default size of the response queue is 8. The get_response method must + // be called soon enough to avoid an overflow of the response queue to prevent + // responses from being dropped. + // + // If a response is dropped in the response queue, an error will be reported + // unless the error reporting is disabled via + // set_response_queue_error_report_enabled. + + // @uvm-ieee 1800.2-2017 auto 14.3.3.3 + virtual task get_response(output RSP response, input int transaction_id = -1); + uvm_sequence_item rsp; + get_base_response( rsp, transaction_id); + $cast(response,rsp); + endtask + + + + // Function- put_response + // + // Internal method. + + virtual function void put_response(uvm_sequence_item response_item); + RSP response; + if (!$cast(response, response_item)) begin + uvm_report_fatal("PUTRSP", "Failure to cast response in put_response", UVM_NONE); + end + put_base_response(response_item); + endfunction + + + // Function- do_print + // + function void do_print (uvm_printer printer); + super.do_print(printer); + printer.print_object("req", req); + printer.print_object("rsp", rsp); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/seq/uvm_sequence_base.svh b/test_regress/t/t_uvm/seq/uvm_sequence_base.svh new file mode 100644 index 0000000000..be6dc18359 --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequence_base.svh @@ -0,0 +1,1274 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2017 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2014-2017 Intel Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013 Verilab +// Copyright 2010-2012 AMD +// Copyright 2012-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, Inc. +// Copyright 2012 Accellera Systems Initiative +// 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_sequence_base +// +// The uvm_sequence_base class provides the interfaces needed to create streams +// of sequence items and/or other sequences. +// +// A sequence is executed by calling its method, either directly +// or invocation of any of the `uvm_do_* macros. +// +// Executing sequences via : +// +// A sequence's method has a ~parent_sequence~ argument that controls +// whether , , and are called *in the parent* +// sequence. It also has a ~call_pre_post~ argument that controls whether its +// and methods are called. +// In all cases, its and methods are always called. +// +// When is called directly, you can provide the appropriate arguments +// according to your application. +// +// The sequence execution flow looks like this +// +// User code +// +//| sub_seq.randomize(...); // optional +//| sub_seq.start(seqr, parent_seq, priority, call_pre_post) +//| +// +// The following methods are called, in order +// +//| +//| sub_seq.pre_start() (task) +//| sub_seq.pre_body() (task) if call_pre_post==1 +//| parent_seq.pre_do(0) (task) if parent_sequence!=null +//| parent_seq.mid_do(this) (func) if parent_sequence!=null +//| sub_seq.body (task) YOUR STIMULUS CODE +//| parent_seq.post_do(this) (func) if parent_sequence!=null +//| sub_seq.post_body() (task) if call_pre_post==1 +//| sub_seq.post_start() (task) +// +// +// Executing sub-sequences via `uvm_do macros: +// +// A sequence can also be indirectly started as a child in the of a +// parent sequence. The child sequence's method is called indirectly +// by invoking any of the `uvm_do macros. +// In these cases, is called with +// ~call_pre_post~ set to 0, preventing the started sequence's and +// methods from being called. During execution of the +// child sequence, the parent's , , and methods +// are called. +// +// The sub-sequence execution flow looks like +// +// User code +// +//| +//| `uvm_do_with_prior(seq_seq, { constraints }, priority) +//| +// +// The following methods are called, in order +// +//| +//| sub_seq.pre_start() (task) +//| parent_seq.pre_do(0) (task) +//| parent_req.mid_do(sub_seq) (func) +//| sub_seq.body() (task) +//| parent_seq.post_do(sub_seq) (func) +//| sub_seq.post_start() (task) +//| +// +// Remember, it is the *parent* sequence's pre|mid|post_do that are called, not +// the sequence being executed. +// +// +// Executing sequence items via / or `uvm_do macros: +// +// Items are started in the of a parent sequence via calls to +// / or invocations of any of the `uvm_do +// macros. The , , and methods of the parent +// sequence will be called as the item is executed. +// +// The sequence-item execution flow looks like +// +// User code +// +//| parent_seq.start_item(item, priority); +//| item.randomize(...) [with {constraints}]; +//| parent_seq.finish_item(item); +//| +//| or +//| +//| `uvm_do_with_prior(item, constraints, priority) +//| +// +// The following methods are called, in order +// +//| +//| sequencer.wait_for_grant(prior) (task) \ start_item \ +//| parent_seq.pre_do(1) (task) / \ +//| `uvm_do* macros +//| parent_seq.mid_do(item) (func) \ / +//| sequencer.send_request(item) (func) \finish_item / +//| sequencer.wait_for_item_done() (task) / +//| parent_seq.post_do(item) (func) / +// +// Attempting to execute a sequence via / +// will produce a run-time error. +//------------------------------------------------------------------------------ + +`ifdef UVM_ENABLE_DEPRECATED_API +class uvm_sequence_base extends uvm_sequence_item; + `uvm_object_utils(uvm_sequence_base) +`else +// Class: uvm_sequence_base +// Implementation of uvm_sequence_base, as defined in section +// 14.2.1 of 1800.2-2017. +// + +// @uvm-ieee 1800.2-2017 auto 14.2.1 +virtual class uvm_sequence_base extends uvm_sequence_item; + `uvm_object_abstract_utils(uvm_sequence_base) +`endif + + + protected uvm_sequence_state m_sequence_state; + int m_next_transaction_id = 1; + local int m_priority = -1; + uvm_recorder m_tr_recorder; + int m_wait_for_grant_semaphore; + + // Each sequencer will assign a sequence id. When a sequence is talking to multiple + // sequencers, each sequence_id is managed separately + protected int m_sqr_seq_ids[int]; + + protected bit children_array[uvm_sequence_base]; + + protected uvm_sequence_item response_queue[$]; + protected int response_queue_depth = 8; + protected bit response_queue_error_report_enabled; + + // Variable -- NODOCS -- do_not_randomize + // + // If set, prevents the sequence from being randomized before being executed + // by the `uvm_do*() and `uvm_rand_send*() macros, + // or as a default sequence. + // +`ifdef UVM_ENABLE_DEPRECATED_API + bit do_not_randomize; +`else + local bit do_not_randomize; +`endif + + protected process m_sequence_process; + local bit m_use_response_handler; + + // bits to detect if is_relevant()/wait_for_relevant() are implemented + local bit is_rel_default; + local bit wait_rel_default; + + + + // @uvm-ieee 1800.2-2017 auto 14.2.2.1 + function new (string name = "uvm_sequence"); + + super.new(name); + m_sequence_state = UVM_CREATED; + m_wait_for_grant_semaphore = 0; + m_init_phase_daps(1); + endfunction + + virtual function bit get_randomize_enabled(); + return (do_not_randomize == 0); + endfunction : get_randomize_enabled + + // @uvm-ieee 1800.2-2017 auto 14.2.2.3 + virtual function void set_randomize_enabled(bit enable); + do_not_randomize = !enable; + endfunction : set_randomize_enabled + + + // Function -- NODOCS -- is_item + // + // Returns 1 on items and 0 on sequences. As this object is a sequence, + // ~is_item~ will always return 0. + // + virtual function bit is_item(); + return 0; + endfunction + + + // Function -- NODOCS -- get_sequence_state + // + // Returns the sequence state as an enumerated value. Can use to wait on + // the sequence reaching or changing from one or more states. + // + //| wait(get_sequence_state() & (UVM_STOPPED|UVM_FINISHED)); + + // @uvm-ieee 1800.2-2017 auto 14.2.2.4 + function uvm_sequence_state_enum get_sequence_state(); + return m_sequence_state; + endfunction + + + // Task -- NODOCS -- wait_for_sequence_state + // + // Waits until the sequence reaches one of the given ~state~. If the sequence + // is already in one of the state, this method returns immediately. + // + //| wait_for_sequence_state(UVM_STOPPED|UVM_FINISHED); + + // @uvm-ieee 1800.2-2017 auto 14.2.2.5 + task wait_for_sequence_state(int unsigned state_mask); + wait (m_sequence_state & state_mask); + endtask + + + // Function -- NODOCS -- get_tr_handle + // + // Returns the integral recording transaction handle for this sequence. + // Can be used to associate sub-sequences and sequence items as + // child transactions when calling . + + function int get_tr_handle(); + if (m_tr_recorder != null) + return m_tr_recorder.get_handle(); + else + return 0; + endfunction + + + //-------------------------- + // Group -- NODOCS -- Sequence Execution + //-------------------------- + + + // Task -- NODOCS -- start + // + // Executes this sequence, returning when the sequence has completed. + // + // The ~sequencer~ argument specifies the sequencer on which to run this + // sequence. The sequencer must be compatible with the sequence. + // + // If ~parent_sequence~ is ~null~, then this sequence is a root parent, + // otherwise it is a child of ~parent_sequence~. The ~parent_sequence~'s + // pre_do, mid_do, and post_do methods will be called during the execution + // of this sequence. + // + // By default, the ~priority~ of a sequence + // is the priority of its parent sequence. + // If it is a root sequence, its default priority is 100. + // A different priority may be specified by ~this_priority~. + // Higher numbers indicate higher priority. + // + // If ~call_pre_post~ is set to 1 (default), then the and + // tasks will be called before and after the sequence + // is called. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.1 + virtual task start (uvm_sequencer_base sequencer, + uvm_sequence_base parent_sequence = null, + int this_priority = -1, + bit call_pre_post = 1); + bit old_automatic_phase_objection; + + set_item_context(parent_sequence, sequencer); + + if (!(m_sequence_state inside {UVM_CREATED,UVM_STOPPED,UVM_FINISHED})) begin + uvm_report_fatal("SEQ_NOT_DONE", + {"Sequence ", get_full_name(), " already started"},UVM_NONE); + end + + if (m_parent_sequence != null) begin + m_parent_sequence.children_array[this] = 1; + end + + if (this_priority < -1) begin + uvm_report_fatal("SEQPRI", $sformatf("Sequence %s start has illegal priority: %0d", + get_full_name(), + this_priority), UVM_NONE); + end + if (this_priority < 0) begin + if (parent_sequence == null) this_priority = 100; + else this_priority = parent_sequence.get_priority(); + end + + // Check that the response queue is empty from earlier runs + clear_response_queue(); + + m_priority = this_priority; + + if (m_sequencer != null) begin + int handle; + if (m_parent_sequence == null) begin + handle = m_sequencer.begin_tr(this, get_name()); + m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle); + end else begin + handle = m_sequencer.begin_tr(.tr(this), .stream_name(get_root_sequence_name()), + .parent_handle((m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle())); + m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle); + end + end + + // Ensure that the sequence_id is intialized in case this sequence has been stopped previously + set_sequence_id(-1); + + // Register the sequence with the sequencer if defined. + if (m_sequencer != null) begin + void'(m_sequencer.m_register_sequence(this)); + end + + // Change the state to PRE_START, do this before the fork so that + // the "if (!(m_sequence_state inside {...}" works + m_sequence_state = UVM_PRE_START; + fork + begin + m_sequence_process = process::self(); + + // absorb delta to ensure PRE_START was seen + #0; + + // Raise the objection if enabled + // (This will lock the uvm_get_to_lock_dap) + if (get_automatic_phase_objection()) begin + m_safe_raise_starting_phase("automatic phase objection"); + end + + pre_start(); + + if (call_pre_post == 1) begin + m_sequence_state = UVM_PRE_BODY; + #0; + pre_body(); + end + + if (parent_sequence != null) begin + parent_sequence.pre_do(0); // task + parent_sequence.mid_do(this); // function + end + + m_sequence_state = UVM_BODY; + #0; + body(); + + m_sequence_state = UVM_ENDED; + #0; + + if (parent_sequence != null) begin + parent_sequence.post_do(this); + end + + if (call_pre_post == 1) begin + m_sequence_state = UVM_POST_BODY; + #0; + post_body(); + end + + m_sequence_state = UVM_POST_START; + #0; + post_start(); + + // Drop the objection if enabled + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + + m_sequence_state = UVM_FINISHED; + #0; + + end + join + + if (m_sequencer != null) begin + m_sequencer.end_tr(this); + end + + // Clean up any sequencer queues after exiting; if we + // were forcibly stopped, this step has already taken place + if (m_sequence_state != UVM_STOPPED) begin + clean_exit_sequence(); + end + + #0; // allow stopped and finish waiters to resume + + if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) begin + m_parent_sequence.children_array.delete(this); + end + + old_automatic_phase_objection = get_automatic_phase_objection(); + m_init_phase_daps(1); + set_automatic_phase_objection(old_automatic_phase_objection); + endtask + + // Function -- NODOCS -- clean_exit_sequence + // This function is for Clean up any sequencer queues after exiting; if we + // were forcibly stopped, this step has already taken place + + function void clean_exit_sequence(); + if (m_sequencer != null) + m_sequencer.m_sequence_exiting(this); + else + // remove any routing for this sequence even when virtual sequencers (or a null sequencer is involved) + // once we pass this point nothing can be routed to this sequence(id) + foreach(m_sqr_seq_ids[seqrID]) begin + uvm_sequencer_base s = uvm_sequencer_base::all_sequencer_insts[seqrID]; + s.m_sequence_exiting(this); + end + m_sqr_seq_ids.delete(); + endfunction + + + // Task -- NODOCS -- pre_start + // + // This task is a user-definable callback that is called before the + // optional execution of . + // This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.2 + virtual task pre_start(); + return; + endtask + + + // Task -- NODOCS -- pre_body + // + // This task is a user-definable callback that is called before the + // execution of ~only~ when the sequence is started with . + // If is called with ~call_pre_post~ set to 0, ~pre_body~ is not + // called. + // This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.3 + virtual task pre_body(); + return; + endtask + + + // Task -- NODOCS -- pre_do + // + // This task is a user-definable callback task that is called ~on the + // parent sequence~, if any + // sequence has issued a wait_for_grant() call and after the sequencer has + // selected this sequence, and before the item is randomized. + // + // Although pre_do is a task, consuming simulation cycles may result in + // unexpected behavior on the driver. + // + // This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.4 + virtual task pre_do(bit is_item); + return; + endtask + + + // Function -- NODOCS -- mid_do + // + // This function is a user-definable callback function that is called after + // the sequence item has been randomized, and just before the item is sent + // to the driver. This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.5 + virtual function void mid_do(uvm_sequence_item this_item); + return; + endfunction + + + // Task -- NODOCS -- body + // + // This is the user-defined task where the main sequence code resides. + // This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.6 + virtual task body(); + uvm_report_warning("uvm_sequence_base", "Body definition undefined"); + return; + endtask + + + // Function -- NODOCS -- post_do + // + // This function is a user-definable callback function that is called after + // the driver has indicated that it has completed the item, using either + // this item_done or put methods. This method should not be called directly + // by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.7 + virtual function void post_do(uvm_sequence_item this_item); + return; + endfunction + + + // Task -- NODOCS -- post_body + // + // This task is a user-definable callback task that is called after the + // execution of ~only~ when the sequence is started with . + // If is called with ~call_pre_post~ set to 0, ~post_body~ is not + // called. + // This task is a user-definable callback task that is called after the + // execution of the body, unless the sequence is started with call_pre_post=0. + // This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.8 + virtual task post_body(); + return; + endtask + + + // Task -- NODOCS -- post_start + // + // This task is a user-definable callback that is called after the + // optional execution of . + // This method should not be called directly by the user. + + // @uvm-ieee 1800.2-2017 auto 14.2.3.9 + virtual task post_start(); + return; + endtask + + + // Group -- NODOCS -- Run-Time Phasing + // + + // Automatic Phase Objection DAP + local uvm_get_to_lock_dap#(bit) m_automatic_phase_objection_dap; + // Starting Phase DAP + local uvm_get_to_lock_dap#(uvm_phase) m_starting_phase_dap; + + // Function- m_init_phase_daps + // Either creates or renames DAPS + function void m_init_phase_daps(bit create); + string apo_name = $sformatf("%s.automatic_phase_objection", get_full_name()); + string sp_name = $sformatf("%s.starting_phase", get_full_name()); + + if (create) begin +`ifdef VERILATOR + m_automatic_phase_objection_dap = uvm_get_to_lock_dap#(bit)::type_id_create(apo_name, get_sequencer()); + m_starting_phase_dap = uvm_get_to_lock_dap#(uvm_phase)::type_id_create(sp_name, get_sequencer()); +`else + m_automatic_phase_objection_dap = uvm_get_to_lock_dap#(bit)::type_id::create(apo_name, get_sequencer()); + m_starting_phase_dap = uvm_get_to_lock_dap#(uvm_phase)::type_id::create(sp_name, get_sequencer()); +`endif + end + else begin + m_automatic_phase_objection_dap.set_name(apo_name); + m_starting_phase_dap.set_name(sp_name); + end + endfunction : m_init_phase_daps + + // Function -- NODOCS -- get_starting_phase + // Returns the 'starting phase'. + // + // If non-~null~, the starting phase specifies the phase in which this + // sequence was started. The starting phase is set automatically when + // this sequence is started as the default sequence on a sequencer. + // See for more information. + // + // Internally, the uses an to + // protect the starting phase value from being modified + // after the reference has been read. Once the sequence has ended + // its execution (either via natural termination, or being killed), + // then the starting phase value can be modified again. + // + // @uvm-ieee 1800.2-2017 auto 14.2.4.1 + function uvm_phase get_starting_phase(); + return m_starting_phase_dap.get(); + endfunction : get_starting_phase + + + // @uvm-ieee 1800.2-2017 auto 14.2.4.2 + function void set_starting_phase(uvm_phase phase); + m_starting_phase_dap.set(phase); + endfunction : set_starting_phase + + + // @uvm-ieee 1800.2-2017 auto 14.2.4.4 + function void set_automatic_phase_objection(bit value); + m_automatic_phase_objection_dap.set(value); + endfunction : set_automatic_phase_objection + + + // @uvm-ieee 1800.2-2017 auto 14.2.4.3 + function bit get_automatic_phase_objection(); + return m_automatic_phase_objection_dap.get(); + endfunction : get_automatic_phase_objection + + // m_safe_raise_starting_phase + function void m_safe_raise_starting_phase(string description = "", + int count = 1); + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) + starting_phase.raise_objection(this, description, count); + endfunction : m_safe_raise_starting_phase + + // m_safe_drop_starting_phase + function void m_safe_drop_starting_phase(string description = "", + int count = 1); + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) + starting_phase.drop_objection(this, description, count); + endfunction : m_safe_drop_starting_phase + + //------------------------ + // Group -- NODOCS -- Sequence Control + //------------------------ + + // Function -- NODOCS -- set_priority + // + // The priority of a sequence may be changed at any point in time. When the + // priority of a sequence is changed, the new priority will be used by the + // sequencer the next time that it arbitrates between sequences. + // + // The default priority value for a sequence is 100. Higher values result + // in higher priorities. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.2 + function void set_priority (int value); + m_priority = value; + endfunction + + + // Function -- NODOCS -- get_priority + // + // This function returns the current priority of the sequence. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.1 + function int get_priority(); + return m_priority; + endfunction + + + // Function -- NODOCS -- is_relevant + // + // The default is_relevant implementation returns 1, indicating that the + // sequence is always relevant. + // + // Users may choose to override with their own virtual function to indicate + // to the sequencer that the sequence is not currently relevant after a + // request has been made. + // + // When the sequencer arbitrates, it will call is_relevant on each requesting, + // unblocked sequence to see if it is relevant. If a 0 is returned, then the + // sequence will not be chosen. + // + // If all requesting sequences are not relevant, then the sequencer will call + // wait_for_relevant on all sequences and re-arbitrate upon its return. + // + // Any sequence that implements is_relevant must also implement + // wait_for_relevant so that the sequencer has a way to wait for a + // sequence to become relevant. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.3 + virtual function bit is_relevant(); + is_rel_default = 1; + return 1; + endfunction + + + // Task -- NODOCS -- wait_for_relevant + // + // This method is called by the sequencer when all available sequences are + // not relevant. When wait_for_relevant returns the sequencer attempt to + // re-arbitrate. + // + // Returning from this call does not guarantee a sequence is relevant, + // although that would be the ideal. The method provide some delay to + // prevent an infinite loop. + // + // If a sequence defines is_relevant so that it is not always relevant (by + // default, a sequence is always relevant), then the sequence must also supply + // a wait_for_relevant method. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.4 + virtual task wait_for_relevant(); + event e; + wait_rel_default = 1; + if (is_rel_default != wait_rel_default) + uvm_report_fatal("RELMSM", + "is_relevant() was implemented without defining wait_for_relevant()", UVM_NONE); +`ifdef VERILATOR + /* verilator lint_off WAITCONST */ + wait(0); +`else + @e; // this is intended to never return +`endif + endtask + + + // Task -- NODOCS -- lock + // + // Requests a lock on the specified sequencer. If sequencer is ~null~, the lock + // will be requested on the current default sequencer. + // + // A lock request will be arbitrated the same as any other request. A lock is + // granted after all earlier requests are completed and no other locks or + // grabs are blocking this sequence. + // + // The lock call will return when the lock has been granted. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.5 + task lock(uvm_sequencer_base sequencer = null); + if (sequencer == null) + sequencer = m_sequencer; + + if (sequencer == null) + uvm_report_fatal("LOCKSEQR", "Null m_sequencer reference", UVM_NONE); + + sequencer.lock(this); + endtask + + + // Task -- NODOCS -- grab + // + // Requests a lock on the specified sequencer. If no argument is supplied, + // the lock will be requested on the current default sequencer. + // + // A grab request is put in front of the arbitration queue. It will be + // arbitrated before any other requests. A grab is granted when no other grabs + // or locks are blocking this sequence. + // + // The grab call will return when the grab has been granted. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.6 + task grab(uvm_sequencer_base sequencer = null); + if (sequencer == null) begin + if (m_sequencer == null) begin + uvm_report_fatal("GRAB", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.grab(this); + end + else begin + sequencer.grab(this); + end + endtask + + + // Function -- NODOCS -- unlock + // + // Removes any locks or grabs obtained by this sequence on the specified + // sequencer. If sequencer is ~null~, then the unlock will be done on the + // current default sequencer. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.7 + function void unlock(uvm_sequencer_base sequencer = null); + if (sequencer == null) begin + if (m_sequencer == null) begin + uvm_report_fatal("UNLOCK", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.unlock(this); + end else begin + sequencer.unlock(this); + end + endfunction + + + // Function -- NODOCS -- ungrab + // + // Removes any locks or grabs obtained by this sequence on the specified + // sequencer. If sequencer is ~null~, then the unlock will be done on the + // current default sequencer. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.8 + function void ungrab(uvm_sequencer_base sequencer = null); + unlock(sequencer); + endfunction + + + // Function -- NODOCS -- is_blocked + // + // Returns a bit indicating whether this sequence is currently prevented from + // running due to another lock or grab. A 1 is returned if the sequence is + // currently blocked. A 0 is returned if no lock or grab prevents this + // sequence from executing. Note that even if a sequence is not blocked, it + // is possible for another sequence to issue a lock or grab before this + // sequence can issue a request. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.9 + function bit is_blocked(); + return m_sequencer.is_blocked(this); + endfunction + + + // Function -- NODOCS -- has_lock + // + // Returns 1 if this sequence has a lock, 0 otherwise. + // + // Note that even if this sequence has a lock, a child sequence may also have + // a lock, in which case the sequence is still blocked from issuing + // operations on the sequencer. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.10 + function bit has_lock(); + return m_sequencer.has_lock(this); + endfunction + + + // Function -- NODOCS -- kill + // + // This function will kill the sequence, and cause all current locks and + // requests in the sequence's default sequencer to be removed. The sequence + // state will change to UVM_STOPPED, and the post_body() and post_start() callback + // methods will not be executed. + // + // If a sequence has issued locks, grabs, or requests on sequencers other than + // the default sequencer, then care must be taken to unregister the sequence + // with the other sequencer(s) using the sequencer unregister_sequence() + // method. + + // @uvm-ieee 1800.2-2017 auto 14.2.5.11 + function void kill(); + if (m_sequence_process != null) begin + // If we are not connected to a sequencer, then issue + // kill locally. + if (m_sequencer == null) begin + m_kill(); + // We need to drop the objection if we raised it... + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + return; + end + // If we are attached to a sequencer, then the sequencer + // will clear out queues, and then kill this sequence + m_sequencer.kill_sequence(this); + // We need to drop the objection if we raised it... + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + return; + end + endfunction + + + // Function: do_kill + // + // Implementation of the do_kill method, as described in P1800.2-2017 + // section 14.2.6.12. + // + // NOTE: do_kill is documented in error in the P1800.2-2017 + // LRM as a non-virtual function, whereas it is implemented as a virtual function + // + // | virtual function void do_kill() + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 14.2.5.12 + virtual function void do_kill(); + return; + endfunction + + function void m_kill(); + do_kill(); + foreach(children_array[i]) begin + i.kill(); + end + if (m_sequence_process != null) begin + m_sequence_process.kill; + m_sequence_process = null; + end + m_sequence_state = UVM_STOPPED; + if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) + m_parent_sequence.children_array.delete(this); + clean_exit_sequence(); + endfunction + + + //------------------------------- + // Group -- NODOCS -- Sequence Item Execution + //------------------------------- + + // Function -- NODOCS -- create_item + // + // Create_item will create and initialize a sequence_item or sequence + // using the factory. The sequence_item or sequence will be initialized + // to communicate with the specified sequencer. + + // @uvm-ieee 1800.2-2017 auto 14.2.6.1 + protected function uvm_sequence_item create_item(uvm_object_wrapper type_var, + uvm_sequencer_base l_sequencer, string name); + + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + $cast(create_item, factory.create_object_by_type( type_var, this.get_full_name(), name )); + + create_item.set_item_context(this, l_sequencer); + endfunction + + + // Function -- NODOCS -- start_item + // + // ~start_item~ and together will initiate operation of + // a sequence item. If the item has not already been + // initialized using create_item, then it will be initialized here to use + // the default sequencer specified by m_sequencer. Randomization + // may be done between start_item and finish_item to ensure late generation + // + + // @uvm-ieee 1800.2-2017 auto 14.2.6.2 + virtual task start_item (uvm_sequence_item item, + int set_priority = -1, + uvm_sequencer_base sequencer=null); + + if(item == null) begin + uvm_report_fatal("NULLITM", + {"attempting to start a null item from sequence '", + get_full_name(), "'"}, UVM_NONE); + return; + end + + if ( ! item.is_item() ) begin + uvm_report_fatal("SEQNOTITM", + {"attempting to start a sequence using start_item() from sequence '", + get_full_name(), "'. Use seq.start() instead."}, UVM_NONE); + return; + end + + if (sequencer == null) + sequencer = item.get_sequencer(); + + if(sequencer == null) + sequencer = get_sequencer(); + + if(sequencer == null) begin + uvm_report_fatal("SEQ",{"neither the item's sequencer nor dedicated sequencer has been supplied to start item in ",get_full_name()},UVM_NONE); + return; + end + + item.set_item_context(this, sequencer); + + if (set_priority < 0) + set_priority = get_priority(); + + sequencer.wait_for_grant(this, set_priority); + + if (sequencer.is_auto_item_recording_enabled()) begin + void'(sequencer.begin_tr(.tr(item), .stream_name(item.get_root_sequence_name()), .label("Transactions"), + .parent_handle((m_tr_recorder == null) ? 0 : m_tr_recorder.get_handle()))); + end + + pre_do(1); + + endtask + + + // Function -- NODOCS -- finish_item + // + // finish_item, together with start_item together will initiate operation of + // a sequence_item. Finish_item must be called + // after start_item with no delays or delta-cycles. Randomization, or other + // functions may be called between the start_item and finish_item calls. + // + + // @uvm-ieee 1800.2-2017 auto 14.2.6.3 + virtual task finish_item (uvm_sequence_item item, + int set_priority = -1); + + uvm_sequencer_base sequencer; + + sequencer = item.get_sequencer(); + + if (sequencer == null) begin + uvm_report_fatal("STRITM", "sequence_item has null sequencer", UVM_NONE); + end + + mid_do(item); + sequencer.send_request(this, item); + sequencer.wait_for_item_done(this, -1); + + if (sequencer.is_auto_item_recording_enabled()) begin + sequencer.end_tr(item); + end + + post_do(item); + + endtask + + + // Task -- NODOCS -- wait_for_grant + // + // This task issues a request to the current sequencer. If item_priority is + // not specified, then the current sequence priority will be used by the + // arbiter. If a lock_request is made, then the sequencer will issue a lock + // immediately before granting the sequence. (Note that the lock may be + // granted without the sequence being granted if is_relevant is not asserted). + // + // When this method returns, the sequencer has granted the sequence, and the + // sequence must call send_request without inserting any simulation delay + // other than delta cycles. The driver is currently waiting for the next + // item to be sent via the send_request call. + + // @uvm-ieee 1800.2-2017 auto 14.2.6.4 + virtual task wait_for_grant(int item_priority = -1, bit lock_request = 0); + if (m_sequencer == null) begin + uvm_report_fatal("WAITGRANT", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.wait_for_grant(this, item_priority, lock_request); + endtask + + + // Function -- NODOCS -- send_request + // + // The send_request function may only be called after a wait_for_grant call. + // This call will send the request item to the sequencer, which will forward + // it to the driver. If the rerandomize bit is set, the item will be + // randomized before being sent to the driver. + + // @uvm-ieee 1800.2-2017 auto 14.2.6.5 + virtual function void send_request(uvm_sequence_item request, bit rerandomize = 0); + if (m_sequencer == null) begin + uvm_report_fatal("SENDREQ", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.send_request(this, request, rerandomize); + endfunction + + + // Task -- NODOCS -- wait_for_item_done + // + // A sequence may optionally call wait_for_item_done. This task will block + // until the driver calls item_done or put. If no transaction_id parameter + // is specified, then the call will return the next time that the driver calls + // item_done or put. If a specific transaction_id is specified, then the call + // will return when the driver indicates completion of that specific item. + // + // Note that if a specific transaction_id has been specified, and the driver + // has already issued an item_done or put for that transaction, then the call + // will hang, having missed the earlier notification. + + + // @uvm-ieee 1800.2-2017 auto 14.2.6.6 + virtual task wait_for_item_done(int transaction_id = -1); + if (m_sequencer == null) begin + uvm_report_fatal("WAITITEMDONE", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.wait_for_item_done(this, transaction_id); + endtask + + + + // Group -- NODOCS -- Response API + //-------------------- + + // Function -- NODOCS -- use_response_handler + // + // When called with enable set to 1, responses will be sent to the response + // handler. Otherwise, responses must be retrieved using get_response. + // + // By default, responses from the driver are retrieved in the sequence by + // calling get_response. + // + // An alternative method is for the sequencer to call the response_handler + // function with each response. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.1 + function void use_response_handler(bit enable); + m_use_response_handler = enable; + endfunction + + + // Function -- NODOCS -- get_use_response_handler + // + // Returns the state of the use_response_handler bit. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.2 + function bit get_use_response_handler(); + return m_use_response_handler; + endfunction + + + // Function -- NODOCS -- response_handler + // + // When the use_response_handler bit is set to 1, this virtual task is called + // by the sequencer for each response that arrives for this sequence. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.3 + virtual function void response_handler(uvm_sequence_item response); + return; + endfunction + + // Function -- NODOCS -- set_response_queue_error_report_enabled + // + // By default, if the internal response queue overflows, an error is + // reported. The response queue will overflow if more responses are + // sent to this from the driver than ~get_response~ calls are made. + // + // Setting the value to '0' disables these errors, while setting it to + // '1' enables them. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.5 + function void set_response_queue_error_report_enabled(bit value); + response_queue_error_report_enabled = value; + endfunction : set_response_queue_error_report_enabled + + // Function -- NODOCS -- get_response_queue_error_report_enabled + // + // When this bit is '1' (default value), error reports are generated when + // the response queue overflows. When this bit is '0', no such error + // reports are generated. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.4 + function bit get_response_queue_error_report_enabled(); + return response_queue_error_report_enabled; + endfunction : get_response_queue_error_report_enabled + +`ifdef UVM_ENABLE_DEPRECATED_API + + // Function- set_response_queue_error_report_disabled + // + // By default, if the response_queue overflows, an error is reported. The + // response_queue will overflow if more responses are sent to this sequence + // from the driver than get_response calls are made. Setting value to 0 + // disables these errors, while setting it to 1 enables them. + + function void set_response_queue_error_report_disabled(bit value); + response_queue_error_report_enabled = value; // Note that the value isn't inverted... confusing given the name of the method, no? That's why we deprecated it. + endfunction + + + // Function- get_response_queue_error_report_disabled + // + // When this bit is 0 (default value), error reports are generated when + // the response queue overflows. When this bit is 1, no such error + // reports are generated. + + function bit get_response_queue_error_report_disabled(); + return !response_queue_error_report_enabled; + endfunction + +`endif // UVM_ENABLE_DEPRECATED_API + + // Function -- NODOCS -- set_response_queue_depth + // + // The default maximum depth of the response queue is 8. These method is used + // to examine or change the maximum depth of the response queue. + // + // Setting the response_queue_depth to -1 indicates an arbitrarily deep + // response queue. No checking is done. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.7 + function void set_response_queue_depth(int value); + response_queue_depth = value; + endfunction + + + // Function -- NODOCS -- get_response_queue_depth + // + // Returns the current depth setting for the response queue. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.6 + function int get_response_queue_depth(); + return response_queue_depth; + endfunction + + + // Function -- NODOCS -- clear_response_queue + // + // Empties the response queue for this sequence. + + // @uvm-ieee 1800.2-2017 auto 14.2.7.8 + virtual function void clear_response_queue(); + response_queue.delete(); + endfunction + + + virtual function void put_base_response(input uvm_sequence_item response); + if ((response_queue_depth == -1) || + (response_queue.size() < response_queue_depth)) begin + response_queue.push_back(response); + return; + end + if (response_queue_error_report_enabled) begin + uvm_report_error(get_full_name(), "Response queue overflow, response was dropped", UVM_NONE); + end + endfunction + + + // Function- put_response + // + // Internal method. + + virtual function void put_response (uvm_sequence_item response_item); + put_base_response(response_item); // no error-checking + endfunction + + + // Function- get_base_response + + virtual task get_base_response(output uvm_sequence_item response, input int transaction_id = -1); + + int queue_size, i; + + if (response_queue.size() == 0) + wait (response_queue.size() != 0); + + if (transaction_id == -1) begin + response = response_queue.pop_front(); + return; + end + + forever begin + queue_size = response_queue.size(); + for (i = 0; i < queue_size; i++) begin + if (response_queue[i].get_transaction_id() == transaction_id) + begin + $cast(response,response_queue[i]); + response_queue.delete(i); + return; + end + end + wait (response_queue.size() != queue_size); + end + endtask + + //---------------------- + // Misc Internal methods + //---------------------- + + + // m_get_sqr_sequence_id + // --------------------- + + function int m_get_sqr_sequence_id(int sequencer_id, bit update_sequence_id); + if (m_sqr_seq_ids.exists(sequencer_id)) begin + if (update_sequence_id == 1) begin + set_sequence_id(m_sqr_seq_ids[sequencer_id]); + end + return m_sqr_seq_ids[sequencer_id]; + end + + if (update_sequence_id == 1) + set_sequence_id(-1); + + return -1; + endfunction + + + // m_set_sqr_sequence_id + // --------------------- + + function void m_set_sqr_sequence_id(int sequencer_id, int sequence_id); + m_sqr_seq_ids[sequencer_id] = sequence_id; + set_sequence_id(sequence_id); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/seq/uvm_sequence_item.svh b/test_regress/t/t_uvm/seq/uvm_sequence_item.svh new file mode 100644 index 0000000000..1b97e1ed13 --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequence_item.svh @@ -0,0 +1,527 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2013 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +//---------------------------------------------------------------------- + +typedef class uvm_sequence_base; +typedef class uvm_sequencer_base; + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_sequence_item +// +// The base class for user-defined sequence items and also the base class for +// the uvm_sequence class. The uvm_sequence_item class provides the basic +// functionality for objects, both sequence items and sequences, to operate in +// the sequence mechanism. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 14.1.1 +class uvm_sequence_item extends uvm_transaction; + + local int m_sequence_id = -1; + protected bit m_use_sequence_info; + protected int m_depth = -1; + protected uvm_sequencer_base m_sequencer; + protected uvm_sequence_base m_parent_sequence; + static bit issued1,issued2; + bit print_sequence_info; + + + // Function -- NODOCS -- new + // + // The constructor method for uvm_sequence_item. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.1 + function new (string name = "uvm_sequence_item"); + super.new(name); + endfunction + + function string get_type_name(); + return "uvm_sequence_item"; + endfunction + + // Macro for factory creation + `uvm_object_registry(uvm_sequence_item, "uvm_sequence_item") + + + // Function- set_sequence_id + + function void set_sequence_id(int id); + m_sequence_id = id; + endfunction + + + // Function -- NODOCS -- get_sequence_id + // + // private + // + // Get_sequence_id is an internal method that is not intended for user code. + // The sequence_id is not a simple integer. The get_transaction_id is meant + // for users to identify specific transactions. + // + // These methods allow access to the sequence_item sequence and transaction + // IDs. get_transaction_id and set_transaction_id are methods on the + // uvm_transaction base_class. These IDs are used to identify sequences to + // the sequencer, to route responses back to the sequence that issued a + // request, and to uniquely identify transactions. + // + // The sequence_id is assigned automatically by a sequencer when a sequence + // initiates communication through any sequencer calls (i.e. `uvm_do_*, + // wait_for_grant). A sequence_id will remain unique for this sequence + // until it ends or it is killed. However, a single sequence may have + // multiple valid sequence ids at any point in time. Should a sequence + // start again after it has ended, it will be given a new unique sequence_id. + // + // The transaction_id is assigned automatically by the sequence each time a + // transaction is sent to the sequencer with the transaction_id in its + // default (-1) value. If the user sets the transaction_id to any non-default + // value, that value will be maintained. + // + // Responses are routed back to this sequences based on sequence_id. The + // sequence may use the transaction_id to correlate responses with their + // requests. + + function int get_sequence_id(); + return (m_sequence_id); + endfunction + + + // Function -- NODOCS -- set_item_context + // + // Set the sequence and sequencer execution context for a sequence item + + // @uvm-ieee 1800.2-2017 auto 14.1.2.2 + function void set_item_context(uvm_sequence_base parent_seq, + uvm_sequencer_base sequencer = null); + set_use_sequence_info(1); + if (parent_seq != null) set_parent_sequence(parent_seq); + if (sequencer == null && m_parent_sequence != null) sequencer = m_parent_sequence.get_sequencer(); + set_sequencer(sequencer); + if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1); + reseed(); + endfunction + + + // Function -- NODOCS -- set_use_sequence_info + // + + // @uvm-ieee 1800.2-2017 auto 14.1.2.3 + function void set_use_sequence_info(bit value); + m_use_sequence_info = value; + endfunction + + + // Function -- NODOCS -- get_use_sequence_info + // + // These methods are used to set and get the status of the use_sequence_info + // bit. Use_sequence_info controls whether the sequence information + // (sequencer, parent_sequence, sequence_id, etc.) is printed, copied, or + // recorded. When use_sequence_info is the default value of 0, then the + // sequence information is not used. When use_sequence_info is set to 1, + // the sequence information will be used in printing and copying. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.3 + function bit get_use_sequence_info(); + return (m_use_sequence_info); + endfunction + + + // Function -- NODOCS -- set_id_info + // + // Copies the sequence_id and transaction_id from the referenced item into + // the calling item. This routine should always be used by drivers to + // initialize responses for future compatibility. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.4 + function void set_id_info(uvm_sequence_item item); + if (item == null) begin + uvm_report_fatal(get_full_name(), "set_id_info called with null parameter", UVM_NONE); + end + this.set_transaction_id(item.get_transaction_id()); + this.set_sequence_id(item.get_sequence_id()); + endfunction + + + // Function -- NODOCS -- set_sequencer + // + // Sets the default sequencer for the sequence to sequencer. It will take + // effect immediately, so it should not be called while the sequence is + // actively communicating with the sequencer. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.6 + virtual function void set_sequencer(uvm_sequencer_base sequencer); + m_sequencer = sequencer; + m_set_p_sequencer(); + endfunction + + + // Function -- NODOCS -- get_sequencer + // + // Returns a reference to the default sequencer used by this sequence. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.5 + function uvm_sequencer_base get_sequencer(); + return m_sequencer; + endfunction + + + // Function -- NODOCS -- set_parent_sequence + // + // Sets the parent sequence of this sequence_item. This is used to identify + // the source sequence of a sequence_item. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.8 + // @uvm-ieee 1800.2-2017 auto 19.1.1.2.10 + function void set_parent_sequence(uvm_sequence_base parent); + m_parent_sequence = parent; + endfunction + + + // Function -- NODOCS -- get_parent_sequence + // + // Returns a reference to the parent sequence of any sequence on which this + // method was called. If this is a parent sequence, the method returns ~null~. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.7 + // @uvm-ieee 1800.2-2017 auto 19.1.1.2.10 + function uvm_sequence_base get_parent_sequence(); + return (m_parent_sequence); + endfunction + + + // Function -- NODOCS -- set_depth + // + // The depth of any sequence is calculated automatically. However, the user + // may use set_depth to specify the depth of a particular sequence. This + // method will override the automatically calculated depth, even if it is + // incorrect. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.10 + function void set_depth(int value); + m_depth = value; + endfunction + + + // Function -- NODOCS -- get_depth + // + // Returns the depth of a sequence from its parent. A parent sequence will + // have a depth of 1, its child will have a depth of 2, and its grandchild + // will have a depth of 3. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.9 + function int get_depth(); + + // If depth has been set or calculated, then use that + if (m_depth != -1) begin + return (m_depth); + end + + // Calculate the depth, store it, and return the value + if (m_parent_sequence == null) begin + m_depth = 1; + end else begin + m_depth = m_parent_sequence.get_depth() + 1; + end + + return (m_depth); + endfunction + + + // Function -- NODOCS -- is_item + // + // This function may be called on any sequence_item or sequence. It will + // return 1 for items and 0 for sequences (which derive from this class). + + // @uvm-ieee 1800.2-2017 auto 14.1.2.11 + virtual function bit is_item(); + return(1); + endfunction + + + // Function- get_full_name + // + // Internal method; overrides must follow same naming convention + + function string get_full_name(); + if(m_parent_sequence != null) + get_full_name = {m_parent_sequence.get_full_name(), "."}; + else if(m_sequencer!=null) + get_full_name = {m_sequencer.get_full_name(), "."}; + if(get_name() != "") + get_full_name = {get_full_name, get_name()}; + else begin + get_full_name = {get_full_name, "_item"}; + end + endfunction + + + // Function -- NODOCS -- get_root_sequence_name + // + // Provides the name of the root sequence (the top-most parent sequence). + + // @uvm-ieee 1800.2-2017 auto 14.1.2.12 + function string get_root_sequence_name(); + uvm_sequence_base root_seq; + root_seq = get_root_sequence(); + if (root_seq == null) + return ""; + else + return root_seq.get_name(); + endfunction + + + // Function- m_set_p_sequencer + // + // Internal method + + virtual function void m_set_p_sequencer(); + return; + endfunction + + + // Function -- NODOCS -- get_root_sequence + // + // Provides a reference to the root sequence (the top-most parent sequence). + + // @uvm-ieee 1800.2-2017 auto 14.1.2.13 + function uvm_sequence_base get_root_sequence(); + uvm_sequence_item root_seq_base; + uvm_sequence_base root_seq; + root_seq_base = this; + while(1) begin + if(root_seq_base.get_parent_sequence()!=null) begin + root_seq_base = root_seq_base.get_parent_sequence(); + $cast(root_seq, root_seq_base); + end + else + return root_seq; + end + endfunction + + + // Function -- NODOCS -- get_sequence_path + // + // Provides a string of names of each sequence in the full hierarchical + // path. A "." is used as the separator between each sequence. + + // @uvm-ieee 1800.2-2017 auto 14.1.2.14 + function string get_sequence_path(); + uvm_sequence_item this_item; + string seq_path; + this_item = this; + seq_path = this.get_name(); + while(1) begin + if(this_item.get_parent_sequence()!=null) begin + this_item = this_item.get_parent_sequence(); + seq_path = {this_item.get_name(), ".", seq_path}; + end + else + return seq_path; + end + endfunction + + + //--------------------------- + // Group -- NODOCS -- Reporting Interface + //--------------------------- + // + // Sequence items and sequences will use the sequencer which they are + // associated with for reporting messages. If no sequencer has been set + // for the item/sequence using or indirectly via + // or ), + // then the global reporter will be used. + + // @uvm-ieee 1800.2-2017 auto 14.1.3.1 + virtual function uvm_report_object uvm_get_report_object(); + if(m_sequencer == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_root(); + end else + return m_sequencer; + endfunction + + // @uvm-ieee 1800.2-2017 auto 14.1.3.2 + function int uvm_report_enabled(int verbosity, + uvm_severity severity=UVM_INFO, string id=""); + uvm_report_object l_report_object = uvm_get_report_object(); + if (l_report_object.get_report_verbosity_level(severity, id) < verbosity) + return 0; + return 1; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 14.1.3.3 + virtual function void uvm_report( uvm_severity severity, + string id, + string message, + int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : + (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report_message l_report_message; + if (report_enabled_checked == 0) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, filename, line, context_name); + uvm_process_report_message(l_report_message); + + endfunction + + // Function -- NODOCS -- uvm_report_info + + // @uvm-ieee 1800.2-2017 auto 14.1.3.3 + virtual function void uvm_report_info( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_INFO, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report_warning + + // @uvm-ieee 1800.2-2017 auto 14.1.3.3 + virtual function void uvm_report_warning( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_WARNING, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report_error + + // @uvm-ieee 1800.2-2017 auto 14.1.3.3 + virtual function void uvm_report_error( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_ERROR, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + + // Function -- NODOCS -- uvm_report_fatal + // + // These are the primary reporting methods in the UVM. uvm_sequence_item + // derived types delegate these functions to their associated sequencer + // if they have one, or to the global reporter. See + // for details on the messaging functions. + + // @uvm-ieee 1800.2-2017 auto 14.1.3.3 + virtual function void uvm_report_fatal( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + + this.uvm_report(UVM_FATAL, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + + // @uvm-ieee 1800.2-2017 auto 14.1.3.4 + virtual function void uvm_process_report_message (uvm_report_message report_message); + uvm_report_object l_report_object = uvm_get_report_object(); + report_message.set_report_object(l_report_object); + if (report_message.get_context() == "") + report_message.set_context(get_sequence_path()); + l_report_object.m_rh.process_report_message(report_message); + endfunction + + + // Function- do_print + // + // Internal method + + function void do_print (uvm_printer printer); + string temp_str0, temp_str1; + int depth = get_depth(); + super.do_print(printer); + if(print_sequence_info || m_use_sequence_info) begin + printer.print_field_int("depth", depth, $bits(depth), UVM_DEC, ".", "int"); + if(m_parent_sequence != null) begin + temp_str0 = m_parent_sequence.get_name(); + temp_str1 = m_parent_sequence.get_full_name(); + end + printer.print_string("parent sequence (name)", temp_str0); + printer.print_string("parent sequence (full name)", temp_str1); + temp_str1 = ""; + if(m_sequencer != null) begin + temp_str1 = m_sequencer.get_full_name(); + end + printer.print_string("sequencer", temp_str1); + end + endfunction + + /* + virtual task pre_do(bit is_item); + return; + endtask + + virtual task body(); + return; + endtask + + virtual function void mid_do(uvm_sequence_item this_item); + return; + endfunction + + virtual function void post_do(uvm_sequence_item this_item); + return; + endfunction + + virtual task wait_for_grant(int item_priority = -1, bit lock_request = 0); + return; + endtask + + virtual function void send_request(uvm_sequence_item request, bit rerandomize = 0); + return; + endfunction + + virtual task wait_for_item_done(int transaction_id = -1); + return; + endtask + */ + +endclass diff --git a/test_regress/t/t_uvm/seq/uvm_sequence_library.svh b/test_regress/t/t_uvm/seq/uvm_sequence_library.svh new file mode 100644 index 0000000000..e4988a9605 --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequence_library.svh @@ -0,0 +1,799 @@ +//---------------------------------------------------------------------- +// Copyright 2011-2017 Mentor Graphics Corporation +// Copyright 2011-2014 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2017 Cisco Systems, 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. +//---------------------------------------------------------------------- + + +typedef class uvm_sequence_library_cfg; + +// +// CLASS -- NODOCS -- uvm_sequence_library +// +// The ~uvm_sequence_library~ is a sequence that contains a list of registered +// sequence types. It can be configured to create and execute these sequences +// any number of times using one of several modes of operation, including a +// user-defined mode. +// +// When started (as any other sequence), the sequence library will randomly +// select and execute a sequence from its ~sequences~ queue. If in +// mode, its property is randomized and used +// as an index into ~sequences~. When in mode, the +// property is used. When in mode, only +// sequence items of the ~REQ~ type are generated and executed--no sequences +// are executed. Finally, when in mode, the +// method is called to obtain the index for selecting the +// next sequence to start. Users can override this method in subtypes to +// implement custom selection algorithms. +// +// Creating a subtype of a sequence library requires invocation of the +// <`uvm_sequence_library_utils> macro in its declaration and calling +// the method in its constructor. The macro +// and function are needed to populate the sequence library with any +// sequences that were statically registered with it or any of its base +// classes. +// +//| class my_seq_lib extends uvm_sequence_library #(my_item); +//| `uvm_object_utils(my_seq_lib) +//| `uvm_sequence_library_utils(my_seq_lib) +//| function new(string name=""); +//| super.new(name); +//| init_sequence_library(); +//| endfunction +//| ... +//| endclass +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 14.4.1 +class uvm_sequence_library #(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequence #(REQ,RSP); + + + `uvm_object_param_utils(uvm_sequence_library#(REQ,RSP)) + `uvm_type_name_decl("uvm_sequence_library #(REQ,RSP)") + + // @uvm-ieee 1800.2-2017 auto 14.4.2 + // @uvm-ieee 1800.2-2017 auto 14.4.3 + extern function new(string name=""); + + + //-------------------------- + // Group -- NODOCS -- Sequence selection + //-------------------------- + + // Variable -- NODOCS -- selection_mode + // + // Specifies the mode used to select sequences for execution + // + // If you do not have access to an instance of the library, + // use the configuration resource interface. + // + // The following example sets the ~config_seq_lib~ as the default + // sequence for the 'main' phase on the sequencer to be + // located at "env.agent.sequencer" + // and set the selection mode to . If the + // settings are being done from within a component, the first + // argument must be ~this~ and the second argument a path + // relative to that component. + // + // + //| uvm_config_db #(uvm_object_wrapper)::set(null, + //| "env.agent.sequencer.main_phase", + //| "default_sequence", + //| main_seq_lib::get_type()); + //| + //| uvm_config_db #(uvm_sequence_lib_mode)::set(null, + //| "env.agent.sequencer.main_phase", + //| "default_sequence.selection_mode", + //| UVM_SEQ_LIB_RANDC); + // + // Alternatively, you may create an instance of the sequence library + // a priori, initialize all its parameters, randomize it, then set it + // to run as-is on the sequencer. + // + //| main_seq_lib my_seq_lib; + //| my_seq_lib = new("my_seq_lib"); + //| + //| my_seq_lib.selection_mode = UVM_SEQ_LIB_RANDC; + //| my_seq_lib.min_random_count = 500; + //| my_seq_lib.max_random_count = 1000; + //| void'(my_seq_lib.randomize()); + //| + //| uvm_config_db #(uvm_sequence_base)::set(null, + //| "env.agent.sequencer.main_phase", + //| "default_sequence", + //| my_seq_lib); + //| + // + uvm_sequence_lib_mode selection_mode; + + + // Variable -- NODOCS -- min_random_count + // + // Sets the minimum number of items to execute. Use the configuration + // mechanism to set. See for an example. + // + int unsigned min_random_count=10; + + + // Variable -- NODOCS -- max_random_count + // + // Sets the maximum number of items to execute. Use the configuration + // mechanism to set. See for an example. + // + // + int unsigned max_random_count=10; + + + + // Variable -- NODOCS -- sequences_executed + // + // Indicates the number of sequences executed, not including the + // currently executing sequence, if any. + // + protected int unsigned sequences_executed; + + + // Variable -- NODOCS -- sequence_count + // + // Specifies the number of sequences to execute when this sequence + // library is started. If in mode, specifies the + // number of sequence items that will be generated. + // + rand int unsigned sequence_count = 10; + + + // Variable -- NODOCS -- select_rand + // + // The index variable that is randomized to select the next sequence + // to execute when in UVM_SEQ_LIB_RAND mode + // + // Extensions may place additional constraints on this variable. + // + rand int unsigned select_rand; + + + // Variable -- NODOCS -- select_randc + // + // The index variable that is randomized to select the next sequence + // to execute when in UVM_SEQ_LIB_RANDC mode + // + // Extensions may place additional constraints on this variable. + // + randc bit [15:0] select_randc; + + + + // Variable- seqs_distrib + // + // + // + protected int seqs_distrib[string] = '{default:0}; + + + // Variable- sequences + // + // The container of all registered sequence types. For + // times, this sequence library will randomly select and execute a + // sequence from this list of sequence types. + // + protected uvm_object_wrapper sequences[$]; + + + + // Constraint: valid_rand_selection + // + // Constrains to be a valid index into the ~sequences~ array + // + constraint valid_rand_selection { + select_rand inside {[0:sequences.size()-1]}; + } + + + + // Constraint: valid_randc_selection + // + // Constrains to be a valid index into the ~sequences~ array + // + constraint valid_randc_selection { + select_randc inside {[0:sequences.size()-1]}; + } + + + // Constraint: valid_sequence_count + // + // Constrains to lie within the range defined by + // and . + // + constraint valid_sequence_count { + sequence_count inside {[min_random_count:max_random_count]}; + } + + + + // Function -- NODOCS -- select_sequence + // + // Generates an index used to select the next sequence to execute. + // Overrides must return a value between 0 and ~max~, inclusive. + // Used only for selection mode. The + // default implementation returns 0, incrementing on successive calls, + // wrapping back to 0 when reaching ~max~. + // + extern virtual function int unsigned select_sequence(int unsigned max); + + + + //----------------------------- + // Group -- NODOCS -- Sequence registration + //----------------------------- + + // Function -- NODOCS -- add_typewide_sequence + // + // Registers the provided sequence type with this sequence library + // type. The sequence type will be available for selection by all instances + // of this class. Sequence types already registered are silently ignored. + // + extern static function void add_typewide_sequence(uvm_object_wrapper seq_type); + + + + + // @uvm-ieee 1800.2-2017 auto 14.4.5.2 + extern static function void add_typewide_sequences(uvm_object_wrapper seq_types[$]); + + + + // @uvm-ieee 1800.2-2017 auto 14.4.5.3 + extern function void add_sequence(uvm_object_wrapper seq_type); + + + + // @uvm-ieee 1800.2-2017 auto 14.4.5.4 + extern virtual function void add_sequences(uvm_object_wrapper seq_types[$]); + + + + // @uvm-ieee 1800.2-2017 auto 14.4.5.5 + extern virtual function void remove_sequence(uvm_object_wrapper seq_type); + + + + // @uvm-ieee 1800.2-2017 auto 14.4.5.6 + extern virtual function void get_sequences(ref uvm_object_wrapper seq_types[$]); + + // @uvm-ieee 1800.2-2017 auto 14.4.4.10 + extern virtual function uvm_object_wrapper get_sequence(int unsigned idx); + + + // Function -- NODOCS -- init_sequence_library + // + // All subtypes of this class must call init_sequence_library in its + // constructor. + extern function void init_sequence_library(); + + // Macro -- NODOCS -- uvm_sequence_library_utils + // + // All subtypes of this class must invoke the `uvm_sequence_library_utils + // macro. + // + //| class my_seq_lib extends uvm_sequence_library #(my_item); + //| `uvm_object_utils(my_seq_lib) + //| `uvm_sequence_library_utils(my_seq_lib) + //| function new(string name=""); + //| super.new(name); + //| init_sequence_library(); + //| endfunction + //| ... + //| endclass + + //------------------------------------------ + // PRIVATE - INTERNAL - NOT PART OF STANDARD + //------------------------------------------ + + typedef uvm_sequence_library #(REQ,RSP) this_type; + + static protected uvm_object_wrapper m_typewide_sequences[$]; + bit m_abort; + + extern static function bit m_static_check(uvm_object_wrapper seq_type); + extern static function bit m_check(uvm_object_wrapper seq_type, this_type lib); + extern function bit m_dyn_check(uvm_object_wrapper seq_type); + extern function void m_get_config(); + extern static function bit m_add_typewide_sequence(uvm_object_wrapper seq_type); + extern virtual task execute(uvm_object_wrapper wrap); + + extern virtual task body(); + extern virtual function void do_print(uvm_printer printer); + extern function void pre_randomize(); + +endclass + + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_sequence_library_cfg +// +// A convenient container class for configuring all the sequence library +// parameters using a single ~set~ command. +// +//| uvm_sequence_library_cfg cfg; +//| cfg = new("seqlib_cfg", UVM_SEQ_LIB_RANDC, 1000, 2000); +//| +//| uvm_config_db #(uvm_sequence_library_cfg)::set(null, +//| "env.agent.sequencer.main_ph", +//| "default_sequence.config", +//| cfg); +//| +//------------------------------------------------------------------------------ + +class uvm_sequence_library_cfg extends uvm_object; + `uvm_object_utils(uvm_sequence_library_cfg) + uvm_sequence_lib_mode selection_mode; + int unsigned min_random_count; + int unsigned max_random_count; + function new(string name="", + uvm_sequence_lib_mode mode=UVM_SEQ_LIB_RAND, + int unsigned min=1, + int unsigned max=10); + super.new(name); + selection_mode = mode; + min_random_count = min; + max_random_count = max; + endfunction +endclass + + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// new +// --- + +function uvm_sequence_library::new(string name=""); + super.new(name); + init_sequence_library(); + valid_rand_selection.constraint_mode(0); + valid_randc_selection.constraint_mode(0); +endfunction + + +// m_add_typewide_sequence +// ----------------------- + +function bit uvm_sequence_library::m_add_typewide_sequence(uvm_object_wrapper seq_type); + this_type::add_typewide_sequence(seq_type); + return 1; +endfunction + + +// add_typewide_sequence +// --------------------- + +function void uvm_sequence_library::add_typewide_sequence(uvm_object_wrapper seq_type); + if (m_static_check(seq_type)) + m_typewide_sequences.push_back(seq_type); +endfunction + + +// add_typewide_sequences +// ---------------------- + +function void uvm_sequence_library::add_typewide_sequences(uvm_object_wrapper seq_types[$]); + foreach (seq_types[i]) + add_typewide_sequence(seq_types[i]); +endfunction + + +// add_sequence +// ------------ + +function void uvm_sequence_library::add_sequence(uvm_object_wrapper seq_type); + if (m_dyn_check(seq_type)) + sequences.push_back(seq_type); +endfunction + + +// add_sequences +// ------------- + +function void uvm_sequence_library::add_sequences(uvm_object_wrapper seq_types[$]); + foreach (seq_types[i]) + add_sequence(seq_types[i]); +endfunction + + +// remove_sequence +// --------------- + +function void uvm_sequence_library::remove_sequence(uvm_object_wrapper seq_type); + foreach (sequences[i]) + if (sequences[i] == seq_type) begin + sequences.delete(i); + return; + end +endfunction + + +// get_sequences +// ------------- + +function void uvm_sequence_library::get_sequences(ref uvm_object_wrapper seq_types[$]); + foreach (sequences[i]) + seq_types.push_back(sequences[i]); +endfunction + +// get_sequence +// ------------ + +function uvm_object_wrapper uvm_sequence_library::get_sequence(int unsigned idx); + if(idx < sequences.size()) + return sequences[idx]; + else begin + `uvm_error("SEQ_LIB/GET_SEQ", $sformatf("idx %0d > number of sequences in library", idx)) + return null; + end + +endfunction + +// select_sequence +// --------------- + +function int unsigned uvm_sequence_library::select_sequence(int unsigned max); + static int unsigned counter; + select_sequence = counter; + counter++; + if (counter >= max) + counter = 0; +endfunction + + +//----------// +// INTERNAL // +//----------// + + +// init_sequence_library +// --------------------- + +function void uvm_sequence_library::init_sequence_library(); + foreach (this_type::m_typewide_sequences[i]) + sequences.push_back(this_type::m_typewide_sequences[i]); +endfunction + + + +// m_static_check +// -------------- + + +function bit uvm_sequence_library::m_static_check(uvm_object_wrapper seq_type); + if (!m_check(seq_type,null)) + return 0; + foreach (m_typewide_sequences[i]) + if (m_typewide_sequences[i] == seq_type) + return 0; + return 1; +endfunction + + +// m_dyn_check +// ----------- + +function bit uvm_sequence_library::m_dyn_check(uvm_object_wrapper seq_type); + if (!m_check(seq_type,this)) + return 0; + foreach (sequences[i]) + if (sequences[i] == seq_type) + return 0; + return 1; +endfunction + + +// m_check +// ------- + +function bit uvm_sequence_library::m_check(uvm_object_wrapper seq_type, this_type lib); + uvm_object obj; + uvm_sequence_base seq; + uvm_root top; + uvm_coreservice_t cs; + string name; + string typ; + obj = seq_type.create_object(); +`ifdef UVM_ENABLE_DEPRECATED_API + name = (lib == null) ? type_name : lib.get_full_name(); + typ = (lib == null) ? type_name : lib.get_type_name(); +`else + name = (lib == null) ? type_name() : lib.get_full_name(); + typ = (lib == null) ? type_name() : lib.get_type_name(); +`endif + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + + if (!$cast(seq, obj)) begin + `uvm_error_context("SEQLIB/BAD_SEQ_TYPE", + {"Object '",obj.get_type_name(), + "' is not a sequence. Cannot add to sequence library '",name, + "'"},top) + return 0; + end + return 1; +endfunction + + +// pre_randomize +// ------------- + +function void uvm_sequence_library::pre_randomize(); + m_get_config(); +endfunction + + +// m_get_config +// ------------ + +function void uvm_sequence_library::m_get_config(); + + uvm_sequence_library_cfg cfg; + string phase_name; + uvm_phase starting_phase = get_starting_phase(); + + if (starting_phase != null) begin + phase_name = {starting_phase.get_name(),"_phase"}; + end + if (uvm_config_db #(uvm_sequence_library_cfg)::get(m_sequencer, + phase_name, + "default_sequence.config", + cfg) ) begin + selection_mode = cfg.selection_mode; + min_random_count = cfg.min_random_count; + max_random_count = cfg.max_random_count; + end + else begin + void'(uvm_config_db #(int unsigned)::get(m_sequencer, + phase_name, + "default_sequence.min_random_count", + min_random_count) ); + + void'(uvm_config_db #(int unsigned)::get(m_sequencer, + phase_name, + "default_sequence.max_random_count", + max_random_count) ); + + void'(uvm_config_db #(uvm_sequence_lib_mode)::get(m_sequencer, + phase_name, + "default_sequence.selection_mode", + selection_mode) ); + end + + if (max_random_count == 0) begin + `uvm_warning("SEQLIB/MAX_ZERO", + $sformatf("max_random_count (%0d) zero. Nothing will be done.", + max_random_count)) + if (min_random_count > max_random_count) + min_random_count = max_random_count; + end + else if (min_random_count > max_random_count) begin + `uvm_error("SEQLIB/MIN_GT_MAX", + $sformatf("min_random_count (%0d) greater than max_random_count (%0d). Setting min to max.", + min_random_count,max_random_count)) + min_random_count = max_random_count; + end + else begin + if (selection_mode == UVM_SEQ_LIB_ITEM) begin + uvm_sequencer #(REQ,RSP) seqr; + uvm_object_wrapper lhs = REQ::get_type(); + uvm_object_wrapper rhs = uvm_sequence_item::get_type(); + if (lhs == rhs) begin + `uvm_error("SEQLIB/BASE_ITEM", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ", + "the REQ type is the base uvm_sequence_item. Using UVM_SEQ_LIB_RAND mode"}) + selection_mode = UVM_SEQ_LIB_RAND; + end + if (m_sequencer == null || !$cast(seqr,m_sequencer)) begin + `uvm_error("SEQLIB/VIRT_SEQ", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ", + "running as a virtual sequence. Using UVM_SEQ_LIB_RAND mode"}) + selection_mode = UVM_SEQ_LIB_RAND; + end + end + end + +endfunction + + +// body +// ---- + +task uvm_sequence_library::body(); + + uvm_object_wrapper wrap; + uvm_phase starting_phase = get_starting_phase(); + + if (m_sequencer == null) begin + `uvm_fatal("SEQLIB/VIRT_SEQ", {"Sequence library 'm_sequencer' handle is null ", + " no current support for running as a virtual sequence."}) + return; + end + + if (sequences.size() == 0) begin + `uvm_error("SEQLIB/NOSEQS", "Sequence library does not contain any sequences. Did you forget to call init_sequence_library() in the constructor?") + return; + end + + if (!get_randomize_enabled()) + m_get_config(); + + m_safe_raise_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"}); + + `uvm_info("SEQLIB/START", + $sformatf("Starting sequence library %s in %s phase: %0d iterations in mode %s", + get_type_name(), + (starting_phase != null ? starting_phase.get_name() : "unknown"), + sequence_count, selection_mode.name()),UVM_LOW) + + `uvm_info("SEQLIB/SPRINT",{"\n",sprint(uvm_table_printer::get_default())},UVM_FULL) + + case (selection_mode) + + UVM_SEQ_LIB_RAND: begin + valid_rand_selection.constraint_mode(1); + valid_sequence_count.constraint_mode(0); + for (int i=1; i<=sequence_count; i++) begin + if (!randomize(select_rand)) begin + `uvm_error("SEQLIB/RAND_FAIL", "Random sequence selection failed") + break; + end + else begin + wrap = sequences[select_rand]; + end + execute(wrap); + end + valid_rand_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + end + + UVM_SEQ_LIB_RANDC: begin + uvm_object_wrapper q[$]; + valid_randc_selection.constraint_mode(1); + valid_sequence_count.constraint_mode(0); + for (int i=1; i<=sequence_count; i++) begin + if (!randomize(select_randc)) begin + `uvm_error("SEQLIB/RANDC_FAIL", "Random sequence selection failed") + break; + end + else begin + wrap = sequences[select_randc]; + end + q.push_back(wrap); + end + valid_randc_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + foreach(q[i]) + execute(q[i]); + valid_randc_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + end + + UVM_SEQ_LIB_ITEM: begin + for (int i=1; i<=sequence_count; i++) begin + wrap = REQ::get_type(); + execute(wrap); + end + end + + UVM_SEQ_LIB_USER: begin + for (int i=1; i<=sequence_count; i++) begin + int user_selection; + user_selection = select_sequence(sequences.size()-1); + if (user_selection >= sequences.size()) begin + `uvm_error("SEQLIB/USER_FAIL", "User sequence selection out of range") + wrap = REQ::get_type(); + end + else begin + wrap = sequences[user_selection]; + end + execute(wrap); + end + end + + default: begin + `uvm_fatal("SEQLIB/RAND_MODE", + $sformatf("Unknown random sequence selection mode: %0d",selection_mode)) + end + endcase + + `uvm_info("SEQLIB/END",{"Ending sequence library in phase ", + (starting_phase != null ? starting_phase.get_name() : "unknown")},UVM_LOW) + + `uvm_info("SEQLIB/DSTRB",$sformatf("%p",seqs_distrib),UVM_HIGH) + + m_safe_drop_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"}); + +endtask + + +// execute +// ------- + +task uvm_sequence_library::execute(uvm_object_wrapper wrap); + + uvm_object obj; + uvm_sequence_item seq_or_item; + uvm_sequence_base seq_base; + REQ req_item; + + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + + obj = factory.create_object_by_type(wrap,get_full_name(), + $sformatf("%s:%0d",wrap.get_type_name(),sequences_executed+1)); + + if (!$cast(seq_base, obj)) begin + // If we're executing an item (not a sequence) + if (!$cast(req_item, obj)) begin + // But it's not our item type (This can happen if we were parameterized with + // a pure virtual type, because we're getting get_type() from the base class) + `uvm_error("SEQLIB/WRONG_ITEM_TYPE", {"The item created by '", get_full_name(), "' when in 'UVM_SEQ_LIB_ITEM' mode doesn't match the REQ type which was passed in to the uvm_sequence_library#(REQ[,RSP]), this can happen if the REQ type which was passed in was a pure-virtual type. Either configure the factory overrides to properly generate items for this sequence library, or do not execute this sequence library in UVM_SEQ_LIB_ITEM mode."}) + return; + end + end + + void'($cast(seq_or_item,obj)); // already qualified, + + `uvm_info("SEQLIB/EXEC",{"Executing ",(seq_or_item.is_item() ? "item " : "sequence "),seq_or_item.get_name(), + " (",seq_or_item.get_type_name(),")"},UVM_FULL) + seq_or_item.print_sequence_info = 1; + `uvm_rand_send(seq_or_item) + seqs_distrib[seq_or_item.get_type_name()] = seqs_distrib[seq_or_item.get_type_name()]+1; + + sequences_executed++; + +endtask + + + +// do_print +// -------- + +function void uvm_sequence_library::do_print(uvm_printer printer); + printer.print_field_int("min_random_count",min_random_count,32,UVM_DEC,,"int unsigned"); + printer.print_field_int("max_random_count",max_random_count,32,UVM_DEC,,"int unsigned"); + printer.print_generic("selection_mode","uvm_sequence_lib_mode",32,selection_mode.name()); + printer.print_field_int("sequence_count",sequence_count,32,UVM_DEC,,"int unsigned"); + + printer.print_array_header("typewide_sequences",m_typewide_sequences.size(),"queue_object_types"); + foreach (m_typewide_sequences[i]) + printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",m_typewide_sequences[i].get_type_name()); + printer.print_array_footer(); + + printer.print_array_header("sequences",sequences.size(),"queue_object_types"); + foreach (sequences[i]) + printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",sequences[i].get_type_name()); + printer.print_array_footer(); + + printer.print_array_header("seqs_distrib",seqs_distrib.num(),"as_int_string"); + foreach (seqs_distrib[typ]) begin + printer.print_field_int({"[",typ,"]"},seqs_distrib[typ],32,,UVM_DEC,"int unsigned"); + end + printer.print_array_footer(); +endfunction diff --git a/test_regress/t/t_uvm/seq/uvm_sequencer.svh b/test_regress/t/t_uvm/seq/uvm_sequencer.svh new file mode 100644 index 0000000000..233523292c --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequencer.svh @@ -0,0 +1,345 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2011 AMD +// Copyright 2014-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, Inc. +// Copyright 2017 Verific +// 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_sequencer #(REQ,RSP) +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 15.5.1 +class uvm_sequencer #(type REQ=uvm_sequence_item, RSP=REQ) + extends uvm_sequencer_param_base #(REQ, RSP); + + typedef uvm_sequencer #( REQ , RSP) this_type; + + bit sequence_item_requested; + bit get_next_item_called; + + `uvm_component_param_utils(this_type) + + + + + // @uvm-ieee 1800.2-2017 auto 15.5.2.2 + extern function new (string name, uvm_component parent=null); + + + // Function -- NODOCS -- stop_sequences + // + // Tells the sequencer to kill all sequences and child sequences currently + // operating on the sequencer, and remove all requests, locks and responses + // that are currently queued. This essentially resets the sequencer to an + // idle state. + // + extern virtual function void stop_sequences(); + + extern virtual function string get_type_name(); + + // Group -- NODOCS -- Sequencer Interface + // This is an interface for communicating with sequencers. + // + // The interface is defined as: + //| Requests: + //| virtual task get_next_item (output REQ request); + //| virtual task try_next_item (output REQ request); + //| virtual task get (output REQ request); + //| virtual task peek (output REQ request); + //| Responses: + //| virtual function void item_done (input RSP response=null); + //| virtual task put (input RSP response); + //| Sync Control: + //| virtual task wait_for_sequences (); + //| virtual function bit has_do_available (); + // + // See for information about this interface. + + // Variable -- NODOCS -- seq_item_export + // + // This export provides access to this sequencer's implementation of the + // sequencer interface. + // + + uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export; + + // Task -- NODOCS -- get_next_item + // Retrieves the next available item from a sequence. + // + extern virtual task get_next_item (output REQ t); + + // Task -- NODOCS -- try_next_item + // Retrieves the next available item from a sequence if one is available. + // + extern virtual task try_next_item (output REQ t); + + // Function -- NODOCS -- item_done + // Indicates that the request is completed. + // + extern virtual function void item_done (RSP item = null); + + // Task -- NODOCS -- put + // Sends a response back to the sequence that issued the request. + // + extern virtual task put (RSP t); + + // Task -- NODOCS -- get + // Retrieves the next available item from a sequence. + // + extern task get (output REQ t); + + // Task -- NODOCS -- peek + // Returns the current request item if one is in the FIFO. + // + extern task peek (output REQ t); + + /// Documented here for clarity, implemented in uvm_sequencer_base + + // Task -- NODOCS -- wait_for_sequences + // Waits for a sequence to have a new item available. + // + + // Function -- NODOCS -- has_do_available + // Returns 1 if any sequence running on this sequencer is ready to supply + // a transaction, 0 otherwise. + // + + //----------------- + // Internal Methods + //----------------- + // Do not use directly, not part of standard + + extern function void item_done_trigger(RSP item = null); + function RSP item_done_get_trigger_data(); + return last_rsp(0); + endfunction + extern protected virtual function int m_find_number_driver_connections(); + +endclass + +`ifdef VERILATOR +typedef uvm_sequencer #(uvm_sequence_item, uvm_sequence_item) uvm_virtual_sequencer; +`else +typedef uvm_sequencer #(uvm_sequence_item) uvm_virtual_sequencer; +`endif + + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +function uvm_sequencer::new (string name, uvm_component parent=null); + super.new(name, parent); + seq_item_export = new ("seq_item_export", this); +endfunction + + +// Function- stop_sequences +// +// Tells the sequencer to kill all sequences and child sequences currently +// operating on the sequencer, and remove all requests, locks and responses +// that are currently queued. This essentially resets the sequencer to an +// idle state. +// +function void uvm_sequencer::stop_sequences(); + REQ t; + super.stop_sequences(); + sequence_item_requested = 0; + get_next_item_called = 0; + // Empty the request fifo + if (m_req_fifo.used()) begin + uvm_report_info(get_full_name(), "Sequences stopped. Removing request from sequencer fifo"); + m_req_fifo.flush(); + end +endfunction + + +function string uvm_sequencer::get_type_name(); + return "uvm_sequencer"; +endfunction + + +//----------------- +// Internal Methods +//----------------- + +// m_find_number_driver_connections +// -------------------------------- +// Counting the number of of connections is done at end of +// elaboration and the start of run. If the user neglects to +// call super in one or the other, the sequencer will still +// have the correct value + +function int uvm_sequencer::m_find_number_driver_connections(); + uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)) provided_to_port_list[string]; + + // Check that the seq_item_pull_port is connected + seq_item_export.get_provided_to(provided_to_port_list); + return provided_to_port_list.num(); +endfunction + + +// get_next_item +// ------------- + +task uvm_sequencer::get_next_item(output REQ t); + REQ req_item; + + // If a sequence_item has already been requested, then get_next_item() + // should not be called again until item_done() has been called. + + if (get_next_item_called == 1) + uvm_report_error(get_full_name(), + "Get_next_item called twice without item_done or get in between", UVM_NONE); + + if (!sequence_item_requested) + m_select_sequence(); + + // Set flag indicating that the item has been requested to ensure that item_done or get + // is called between requests + sequence_item_requested = 1; + get_next_item_called = 1; + m_req_fifo.peek(t); +endtask + + +// try_next_item +// ------------- + +task uvm_sequencer::try_next_item(output REQ t); + int selected_sequence; + time arb_time; + uvm_sequence_base seq; + + if (get_next_item_called == 1) begin + uvm_report_error(get_full_name(), "get_next_item/try_next_item called twice without item_done or get in between", UVM_NONE); + return; + end + + // allow state from last transaction to settle such that sequences' + // relevancy can be determined with up-to-date information + wait_for_sequences(); + + // choose the sequence based on relevancy + selected_sequence = m_choose_next_request(); + + // return if none available + if (selected_sequence == -1) begin + t = null; + return; + end + + // now, allow chosen sequence to resume + m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id); + seq = arb_sequence_q[selected_sequence].sequence_ptr; + arb_sequence_q.delete(selected_sequence); + m_update_lists(); + sequence_item_requested = 1; + get_next_item_called = 1; + + // give it one NBA to put a new item in the fifo + wait_for_sequences(); + + // attempt to get the item; if it fails, produce an error and return + if (!m_req_fifo.try_peek(t)) + uvm_report_error("TRY_NEXT_BLOCKED", {"try_next_item: the selected sequence '", + seq.get_full_name(), "' did not produce an item within an NBA delay. ", + "Sequences should not consume time between calls to start_item and finish_item. ", + "Returning null item."}, UVM_NONE); + +endtask + + +// item_done +// --------- + +function void uvm_sequencer::item_done(RSP item = null); + REQ t; + + // Set flag to allow next get_next_item or peek to get a new sequence_item + sequence_item_requested = 0; + get_next_item_called = 0; + + if (m_req_fifo.try_get(t) == 0) begin + uvm_report_fatal("SQRBADITMDN", {"Item_done() called with no outstanding requests.", + " Each call to item_done() must be paired with a previous call to get_next_item()."}); + end else begin + m_wait_for_item_sequence_id = t.get_sequence_id(); + m_wait_for_item_transaction_id = t.get_transaction_id(); + end + + if (item != null) begin + seq_item_export.put_response(item); + end + + // Grant any locks as soon as possible + grant_queued_locks(); +endfunction + + +// put +// --- + +task uvm_sequencer::put (RSP t); + put_response(t); +endtask + + +// get +// --- + +task uvm_sequencer::get(output REQ t); + if (sequence_item_requested == 0) begin + m_select_sequence(); + end + sequence_item_requested = 1; + m_req_fifo.peek(t); + item_done(); +endtask + + +// peek +// ---- + +task uvm_sequencer::peek(output REQ t); + + if (sequence_item_requested == 0) begin + m_select_sequence(); + end + + // Set flag indicating that the item has been requested to ensure that item_done or get + // is called between requests + sequence_item_requested = 1; + m_req_fifo.peek(t); +endtask + + +// item_done_trigger +// ----------------- + +function void uvm_sequencer::item_done_trigger(RSP item = null); + item_done(item); +endfunction diff --git a/test_regress/t/t_uvm/seq/uvm_sequencer_analysis_fifo.svh b/test_regress/t/t_uvm/seq/uvm_sequencer_analysis_fifo.svh new file mode 100644 index 0000000000..b7697bfa91 --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequencer_analysis_fifo.svh @@ -0,0 +1,38 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, 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 uvm_sequencer_analysis_fifo #(type RSP = uvm_sequence_item) extends uvm_tlm_fifo #(RSP); + + uvm_analysis_imp #(RSP, uvm_sequencer_analysis_fifo #(RSP)) analysis_export; + uvm_sequencer_base sequencer_ptr; + + function new (string name, uvm_component parent = null); + super.new(name, parent, 0); + analysis_export = new ("analysis_export", this); + endfunction + + function void write(input RSP t); + if (sequencer_ptr == null) + uvm_report_fatal ("SEQRNULL", "The sequencer pointer is null when attempting a write", UVM_NONE); + sequencer_ptr.analysis_write(t); + endfunction // void +endclass diff --git a/test_regress/t/t_uvm/seq/uvm_sequencer_base.svh b/test_regress/t/t_uvm/seq/uvm_sequencer_base.svh new file mode 100644 index 0000000000..8ee1bbabbd --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequencer_base.svh @@ -0,0 +1,1433 @@ +//---------------------------------------------------------------------- +// Copyright 2007-2017 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2014 Intel Corporation +// Copyright 2010-2017 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013 Verilab +// Copyright 2010-2012 AMD +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2013-2018 Cisco Systems, Inc. +// Copyright 2012 Accellera Systems Initiative +// 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. +//---------------------------------------------------------------------- + +typedef uvm_config_db#(uvm_sequence_base) uvm_config_seq; +typedef class uvm_sequence_request; + +// Utility class for tracking default_sequences +class uvm_sequence_process_wrapper; + process pid; + uvm_sequence_base seq; +endclass : uvm_sequence_process_wrapper + +//------------------------------------------------------------------------------ +// +// CLASS: uvm_sequencer_base +// +// The library implements some public API beyond what is documented +// in 1800.2. It also modifies some API described erroneously in 1800.2. +// +//------------------------------------------------------------------------------ +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +// @uvm-ieee 1800.2-2017 auto 15.3.1 +class uvm_sequencer_base extends uvm_component; + + typedef enum {SEQ_TYPE_REQ, + SEQ_TYPE_LOCK} seq_req_t; + +// queue of sequences waiting for arbitration + protected uvm_sequence_request arb_sequence_q[$]; + + protected bit arb_completed[int]; + + protected uvm_sequence_base lock_list[$]; + protected uvm_sequence_base reg_sequences[int]; + protected int m_sequencer_id; + protected int m_lock_arb_size; // used for waiting processes + protected int m_arb_size; // used for waiting processes + protected int m_wait_for_item_sequence_id, + m_wait_for_item_transaction_id; + protected int m_wait_relevant_count = 0 ; + protected int m_max_zero_time_wait_relevant_count = 10; + protected time m_last_wait_relevant_time = 0 ; + + local uvm_sequencer_arb_mode m_arbitration = UVM_SEQ_ARB_FIFO; + local static int g_request_id; + local static int g_sequence_id = 1; + local static int g_sequencer_id = 1; + + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for uvm_component: name is the name of the + // instance, and parent is the handle to the hierarchical parent. + + // @uvm-ieee 1800.2-2017 auto 15.3.2.1 + extern function new (string name, uvm_component parent); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.2 + extern function bit is_child (uvm_sequence_base parent, uvm_sequence_base child); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.3 + extern virtual function int user_priority_arbitration(int avail_sequences[$]); + + + // Task -- NODOCS -- execute_item + // + // Executes the given transaction ~item~ directly on this sequencer. A temporary + // parent sequence is automatically created for the ~item~. There is no capability to + // retrieve responses. If the driver returns responses, they will accumulate in the + // sequencer, eventually causing response overflow unless + // is called. + + // @uvm-ieee 1800.2-2017 auto 15.3.2.5 + extern virtual task execute_item(uvm_sequence_item item); + + // Hidden array, keeps track of running default sequences + protected uvm_sequence_process_wrapper m_default_sequences[uvm_phase]; + + // Function -- NODOCS -- start_phase_sequence + // + // Start the default sequence for this phase, if any. + // The default sequence is configured via resources using + // either a sequence instance or sequence type (object wrapper). + // If both are used, + // the sequence instance takes precedence. When attempting to override + // a previous default sequence setting, you must override both + // the instance and type (wrapper) resources, else your override may not + // take effect. + // + // When setting the resource using ~set~, the 1st argument specifies the + // context pointer, usually ~this~ for components or ~null~ when executed from + // outside the component hierarchy (i.e. in module). + // The 2nd argument is the instance string, which is a path name to the + // target sequencer, relative to the context pointer. The path must include + // the name of the phase with a "_phase" suffix. The 3rd argument is the + // resource name, which is "default_sequence". The 4th argument is either + // an object wrapper for the sequence type, or an instance of a sequence. + // + // Configuration by instances + // allows pre-initialization, setting rand_mode, use of inline + // constraints, etc. + // + //| myseq_t myseq = new("myseq"); + //| myseq.randomize() with { ... }; + //| uvm_config_db #(uvm_sequence_base)::set(null, "top.agent.myseqr.main_phase", + //| "default_sequence", + //| myseq); + // + // Configuration by type is shorter and can be substituted via + // the factory. + // + //| uvm_config_db #(uvm_object_wrapper)::set(null, "top.agent.myseqr.main_phase", + //| "default_sequence", + //| myseq_type::type_id::get()); + // + // The uvm_resource_db can similarly be used. + // + //| myseq_t myseq = new("myseq"); + //| myseq.randomize() with { ... }; + //| uvm_resource_db #(uvm_sequence_base)::set({get_full_name(), ".myseqr.main_phase", + //| "default_sequence", + //| myseq, this); + // + //| uvm_resource_db #(uvm_object_wrapper)::set({get_full_name(), ".myseqr.main_phase", + //| "default_sequence", + //| myseq_t::type_id::get(), + //| this ); + // + // + + + + extern virtual function void start_phase_sequence(uvm_phase phase); + + // Function -- NODOCS -- stop_phase_sequence + // + // Stop the default sequence for this phase, if any exists, and it + // is still executing. + + extern virtual function void stop_phase_sequence(uvm_phase phase); + + + + // Task -- NODOCS -- wait_for_grant + // + // This task issues a request for the specified sequence. If item_priority + // is not specified, then the current sequence priority will be used by the + // arbiter. If a lock_request is made, then the sequencer will issue a lock + // immediately before granting the sequence. (Note that the lock may be + // granted without the sequence being granted if is_relevant is not asserted). + // + // When this method returns, the sequencer has granted the sequence, and the + // sequence must call send_request without inserting any simulation delay + // other than delta cycles. The driver is currently waiting for the next + // item to be sent via the send_request call. + + // @uvm-ieee 1800.2-2017 auto 15.3.2.6 + extern virtual task wait_for_grant(uvm_sequence_base sequence_ptr, + int item_priority = -1, + bit lock_request = 0); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.7 + extern virtual task wait_for_item_done(uvm_sequence_base sequence_ptr, + int transaction_id); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.8 + extern function bit is_blocked(uvm_sequence_base sequence_ptr); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.9 + extern function bit has_lock(uvm_sequence_base sequence_ptr); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.10 + extern virtual task lock(uvm_sequence_base sequence_ptr); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.11 + extern virtual task grab(uvm_sequence_base sequence_ptr); + + + + // Function: unlock + // + //| extern virtual function void unlock(uvm_sequence_base sequence_ptr); + // + // Implementation of unlock, as defined in P1800.2-2017 section 15.3.2.12. + // + // NOTE: unlock is documented in error as a virtual task, whereas it is + // implemented as a virtual function. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 15.3.2.12 + extern virtual function void unlock(uvm_sequence_base sequence_ptr); + + + // Function: ungrab + // + //| extern virtual function void ungrab(uvm_sequence_base sequence_ptr); + // + // Implementation of ungrab, as defined in P1800.2-2017 section 15.3.2.13. + // + // NOTE: ungrab is documented in error as a virtual task, whereas it is + // implemented as a virtual function. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + // @uvm-ieee 1800.2-2017 auto 15.3.2.13 + extern virtual function void ungrab(uvm_sequence_base sequence_ptr); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.14 + extern virtual function void stop_sequences(); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.15 + extern virtual function bit is_grabbed(); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.16 + extern virtual function uvm_sequence_base current_grabber(); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.17 + extern virtual function bit has_do_available(); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.19 + extern function void set_arbitration(UVM_SEQ_ARB_TYPE val); + + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.18 + extern function UVM_SEQ_ARB_TYPE get_arbitration(); + + + // Task -- NODOCS -- wait_for_sequences + // + // Waits for a sequence to have a new item available. Uses + // to give a sequence as much time as + // possible to deliver an item before advancing time. + + extern virtual task wait_for_sequences(); + + + // Function -- NODOCS -- send_request + // + // Derived classes implement this function to send a request item to the + // sequencer, which will forward it to the driver. If the rerandomize bit + // is set, the item will be randomized before being sent to the driver. + // + // This function may only be called after a call. + + // @uvm-ieee 1800.2-2017 auto 15.3.2.20 + extern virtual function void send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + + + // @uvm-ieee 1800.2-2017 auto 15.3.2.21 + extern virtual function void set_max_zero_time_wait_relevant_count(int new_val) ; + + // Added in IEEE. Not in UVM 1.2 + // @uvm-ieee 1800.2-2017 auto 15.3.2.4 + extern virtual function uvm_sequence_base get_arbitration_sequence( int index ); + + //---------------------------------------------------------------------------- + // INTERNAL METHODS - DO NOT CALL DIRECTLY, ONLY OVERLOAD IF VIRTUAL + //---------------------------------------------------------------------------- + + extern protected function void grant_queued_locks(); + + + extern protected task m_select_sequence(); + extern protected function int m_choose_next_request(); + extern task m_wait_for_arbitration_completed(int request_id); + extern function void m_set_arbitration_completed(int request_id); + + + extern local task m_lock_req(uvm_sequence_base sequence_ptr, bit lock); + + + // Task- m_unlock_req + // + // Called by a sequence to request an unlock. This + // will remove a lock for this sequence if it exists + + extern function void m_unlock_req(uvm_sequence_base sequence_ptr); + + + extern local function void remove_sequence_from_queues(uvm_sequence_base sequence_ptr); + extern function void m_sequence_exiting(uvm_sequence_base sequence_ptr); + extern function void kill_sequence(uvm_sequence_base sequence_ptr); + + extern virtual function void analysis_write(uvm_sequence_item t); + + + extern function void do_print (uvm_printer printer); + + + extern virtual function int m_register_sequence(uvm_sequence_base sequence_ptr); + extern protected + virtual function void m_unregister_sequence(int sequence_id); + extern protected function + uvm_sequence_base m_find_sequence(int sequence_id); + + extern protected function void m_update_lists(); + extern function string convert2string(); + extern protected + virtual function int m_find_number_driver_connections(); + extern protected task m_wait_arb_not_equal(); + extern protected task m_wait_for_available_sequence(); + extern protected function int m_get_seq_item_priority(uvm_sequence_request seq_q_entry); + + int m_is_relevant_completed; + +`ifdef UVM_DISABLE_RECORDING + `define UVM_DISABLE_AUTO_ITEM_RECORDING +`endif + +// Macro: UVM_DISABLE_AUTO_ITEM_RECORDING +// Performs the same function as the 1800.2 define UVM_DISABLE_RECORDING, +// globally turning off automatic item recording when defined by the user. +// Provided for backward compatibility. +// +// @uvm-contrib This API is being considered for potential contribution to 1800.2 + +`ifdef UVM_DISABLE_AUTO_ITEM_RECORDING + local bit m_auto_item_recording = 0; +`else + local bit m_auto_item_recording = 1; +`endif + + + // Access to following internal methods provided via seq_item_export + + // Function: disable_auto_item_recording + // + // Disables auto_item_recording + // + // This function is the implementation of the + // uvm_sqr_if_base::disable_auto_item_recording() method detailed in + // IEEE1800.2 section 15.2.1.2.10 + // + // This function is implemented here to allow + // and access to the call. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + virtual function void disable_auto_item_recording(); + m_auto_item_recording = 0; + endfunction + + // Function: is_auto_item_recording_enabled + // + // Returns 1 is auto_item_recording is enabled, + // otherwise 0 + // + // This function is the implementation of the + // uvm_sqr_if_base::is_auto_item_recording_enabled() method detailed in + // IEEE1800.2 section 15.2.1.2.11 + // + // This function is implemented here to allow + // and access to the call. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + virtual function bit is_auto_item_recording_enabled(); + return m_auto_item_recording; + endfunction + + static uvm_sequencer_base all_sequencer_insts[int unsigned]; +endclass + + + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + + +// new +// --- + +function uvm_sequencer_base::new (string name, uvm_component parent); + super.new(name, parent); + m_sequencer_id = g_sequencer_id++; + m_lock_arb_size = -1; + all_sequencer_insts[m_sequencer_id]=this; +endfunction + + +// do_print +// -------- + +function void uvm_sequencer_base::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_array_header("arbitration_queue", arb_sequence_q.size()); + foreach (arb_sequence_q[i]) + printer.print_string($sformatf("[%0d]", i), + $sformatf("%s@seqid%0d",arb_sequence_q[i].request.name(),arb_sequence_q[i].sequence_id), "["); + printer.print_array_footer(arb_sequence_q.size()); + + printer.print_array_header("lock_queue", lock_list.size()); + foreach(lock_list[i]) + printer.print_string($sformatf("[%0d]", i), + $sformatf("%s@seqid%0d",lock_list[i].get_full_name(),lock_list[i].get_sequence_id()), "["); + printer.print_array_footer(lock_list.size()); +endfunction + + +// m_update_lists +// -------------- + +function void uvm_sequencer_base::m_update_lists(); + m_lock_arb_size++; +endfunction + + +// convert2string +// ---------------- + +function string uvm_sequencer_base::convert2string(); + string s; + + $sformat(s, " -- arb i/id/type: "); + foreach (arb_sequence_q[i]) begin + $sformat(s, "%s %0d/%0d/%s ", s, i, arb_sequence_q[i].sequence_id, arb_sequence_q[i].request.name()); + end + $sformat(s, "%s\n -- lock_list i/id: ", s); + foreach (lock_list[i]) begin + $sformat(s, "%s %0d/%0d",s, i, lock_list[i].get_sequence_id()); + end + return(s); +endfunction + + + +// m_find_number_driver_connections +// -------------------------------- + +function int uvm_sequencer_base::m_find_number_driver_connections(); + return 0; +endfunction + + +// m_register_sequence +// ------------------- + +function int uvm_sequencer_base::m_register_sequence(uvm_sequence_base sequence_ptr); + + if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0) + return sequence_ptr.get_sequence_id(); + + sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, g_sequence_id++); + reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr; + return sequence_ptr.get_sequence_id(); +endfunction + + +// m_find_sequence +// --------------- + +function uvm_sequence_base uvm_sequencer_base::m_find_sequence(int sequence_id); + uvm_sequence_base seq_ptr; + int i; + + // When sequence_id is -1, return the first available sequence. This is used + // when deleting all sequences + if (sequence_id == -1) begin + if (reg_sequences.first(i)) begin + return(reg_sequences[i]); + end + return(null); + end + + if (!reg_sequences.exists(sequence_id)) + return null; + return reg_sequences[sequence_id]; +endfunction + + +// m_unregister_sequence +// --------------------- + +function void uvm_sequencer_base::m_unregister_sequence(int sequence_id); + if (!reg_sequences.exists(sequence_id)) + return; + reg_sequences.delete(sequence_id); +endfunction + + +// user_priority_arbitration +// ------------------------- + +function int uvm_sequencer_base::user_priority_arbitration(int avail_sequences[$]); + return avail_sequences[0]; +endfunction + + +// grant_queued_locks +// ------------------ +// Any lock or grab requests that are at the front of the queue will be +// granted at the earliest possible time. This function grants any queues +// at the front that are not locked out + +function void uvm_sequencer_base::grant_queued_locks(); + // remove and report any zombies + begin + uvm_sequence_request zombies[$]; + zombies = arb_sequence_q.find(item) with (item.request==SEQ_TYPE_LOCK && item.process_id.status inside {process::KILLED,process::FINISHED}); + foreach(zombies[idx]) begin + `uvm_error("SEQLCKZMB", $sformatf("The task responsible for requesting a lock on sequencer '%s' for sequence '%s' has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues", this.get_full_name(), zombies[idx].sequence_ptr.get_full_name())) + remove_sequence_from_queues(zombies[idx].sequence_ptr); + end + end + + // grant the first lock request that is not blocked, if any + begin + int lock_req_indices[$]; + lock_req_indices = arb_sequence_q.find_first_index(item) with (item.request==SEQ_TYPE_LOCK && is_blocked(item.sequence_ptr) == 0); + if(lock_req_indices.size()) begin + uvm_sequence_request lock_req = arb_sequence_q[lock_req_indices[0]]; + lock_list.push_back(lock_req.sequence_ptr); + m_set_arbitration_completed(lock_req.request_id); + arb_sequence_q.delete(lock_req_indices[0]); + m_update_lists(); + end + end +endfunction + + +// m_select_sequence +// ----------------- + +task uvm_sequencer_base::m_select_sequence(); + int selected_sequence; + + // Select a sequence + do begin + wait_for_sequences(); + selected_sequence = m_choose_next_request(); + if (selected_sequence == -1) begin + m_wait_for_available_sequence(); + end + end while (selected_sequence == -1); + // issue grant + if (selected_sequence >= 0) begin + m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id); + arb_sequence_q.delete(selected_sequence); + m_update_lists(); + end +endtask + + +// m_choose_next_request +// --------------------- +// When a driver requests an operation, this function must find the next +// available, unlocked, relevant sequence. +// +// This function returns -1 if no sequences are available or the entry into +// arb_sequence_q for the chosen sequence + +function int uvm_sequencer_base::m_choose_next_request(); + int i, temp; + int avail_sequence_count; + int sum_priority_val; + int avail_sequences[$]; + int highest_sequences[$]; + int highest_pri; + string s; + + avail_sequence_count = 0; + + grant_queued_locks(); + + i = 0; + while (i < arb_sequence_q.size()) begin + if ((arb_sequence_q[i].process_id.status == process::KILLED) || + (arb_sequence_q[i].process_id.status == process::FINISHED)) begin + `uvm_error("SEQREQZMB", $sformatf("The task responsible for requesting a wait_for_grant on sequencer '%s' for sequence '%s' has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues", this.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name())) + remove_sequence_from_queues(arb_sequence_q[i].sequence_ptr); + continue; + end + + if (i < arb_sequence_q.size()) + if (arb_sequence_q[i].request == SEQ_TYPE_REQ) + if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) + if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin + if (m_arbitration == UVM_SEQ_ARB_FIFO) begin + return i; + end + else avail_sequences.push_back(i); + end + + i++; + end + + // Return immediately if there are 0 or 1 available sequences + if (m_arbitration == UVM_SEQ_ARB_FIFO) begin + return -1; + end + if (avail_sequences.size() < 1) begin + return -1; + end + + if (avail_sequences.size() == 1) begin + return avail_sequences[0]; + end + + // If any locks are in place, then the available queue must + // be checked to see if a lock prevents any sequence from proceeding + if (lock_list.size() > 0) begin + for (i = 0; i < avail_sequences.size(); i++) begin + if (is_blocked(arb_sequence_q[avail_sequences[i]].sequence_ptr) != 0) begin + avail_sequences.delete(i); + i--; + end + end + if (avail_sequences.size() < 1) + return -1; + if (avail_sequences.size() == 1) + return avail_sequences[0]; + end + + // Weighted Priority Distribution + // Pick an available sequence based on weighted priorities of available sequences + if (m_arbitration == UVM_SEQ_ARB_WEIGHTED) begin + sum_priority_val = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + + temp = $urandom_range(sum_priority_val-1, 0); + + sum_priority_val = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + if ((m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) + + sum_priority_val) > temp) begin + return avail_sequences[i]; + end + sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + uvm_report_fatal("Sequencer", "UVM Internal error in weighted arbitration code", UVM_NONE); + end + + // Random Distribution + if (m_arbitration == UVM_SEQ_ARB_RANDOM) begin + i = $urandom_range(avail_sequences.size()-1, 0); + return avail_sequences[i]; + end + + // Strict Fifo + if ((m_arbitration == UVM_SEQ_ARB_STRICT_FIFO) || m_arbitration == UVM_SEQ_ARB_STRICT_RANDOM) begin + highest_pri = 0; + // Build a list of sequences at the highest priority + for (i = 0; i < avail_sequences.size(); i++) begin + if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) > highest_pri) begin + // New highest priority, so start new list + highest_sequences.delete(); + highest_sequences.push_back(avail_sequences[i]); + highest_pri = m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + else if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) == highest_pri) begin + highest_sequences.push_back(avail_sequences[i]); + end + end + + // Now choose one based on arbitration type + if (m_arbitration == UVM_SEQ_ARB_STRICT_FIFO) begin + return(highest_sequences[0]); + end + + i = $urandom_range(highest_sequences.size()-1, 0); + return highest_sequences[i]; + end + + if (m_arbitration == UVM_SEQ_ARB_USER) begin + i = user_priority_arbitration( avail_sequences); + + // Check that the returned sequence is in the list of available sequences. Failure to + // use an available sequence will cause highly unpredictable results. + highest_sequences = avail_sequences.find with (item == i); + if (highest_sequences.size() == 0) begin + uvm_report_fatal("Sequencer", + $sformatf("Error in User arbitration, sequence %0d not available\n%s", + i, convert2string()), UVM_NONE); + end + return(i); + end + + uvm_report_fatal("Sequencer", "Internal error: Failed to choose sequence", UVM_NONE); + +endfunction + + +// m_wait_arb_not_equal +// -------------------- + +task uvm_sequencer_base::m_wait_arb_not_equal(); + wait (m_arb_size != m_lock_arb_size); +endtask + + +// m_wait_for_available_sequence +// ----------------------------- + +task uvm_sequencer_base::m_wait_for_available_sequence(); + int i; + int is_relevant_entries[$]; + + // This routine will wait for a change in the request list, or for + // wait_for_relevant to return on any non-relevant, non-blocked sequence + m_arb_size = m_lock_arb_size; + + for (i = 0; i < arb_sequence_q.size(); i++) begin + if (arb_sequence_q[i].request == SEQ_TYPE_REQ) begin + if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) begin + if (arb_sequence_q[i].sequence_ptr.is_relevant() == 0) begin + is_relevant_entries.push_back(i); + end + end + end + end + + // Typical path - don't need fork if all queued entries are relevant + if (is_relevant_entries.size() == 0) begin + m_wait_arb_not_equal(); + return; + end + + fork // isolate inner fork block for disabling + begin + fork + begin + fork + begin + // One path in fork is for any wait_for_relevant to return + m_is_relevant_completed = 0; + + for(i = 0; i < is_relevant_entries.size(); i++) begin + fork + automatic int k = i; + + begin + arb_sequence_q[is_relevant_entries[k]].sequence_ptr.wait_for_relevant(); + if ($realtime != m_last_wait_relevant_time) begin + m_last_wait_relevant_time = $realtime ; + m_wait_relevant_count = 0 ; + end + else begin + m_wait_relevant_count++ ; + if (m_wait_relevant_count > m_max_zero_time_wait_relevant_count) begin + `uvm_fatal("SEQRELEVANTLOOP",$sformatf("Zero time loop detected, passed wait_for_relevant %0d times without time advancing",m_wait_relevant_count)) + end + end + m_is_relevant_completed = 1; + end + join_none + + end + wait (m_is_relevant_completed > 0); + end + + // The other path in the fork is for any queue entry to change + begin + m_wait_arb_not_equal(); + end + join_any + end + join_any + disable fork; + end + join +endtask + + +// m_get_seq_item_priority +// ----------------------- + +function int uvm_sequencer_base::m_get_seq_item_priority(uvm_sequence_request seq_q_entry); + // If the priority was set on the item, then that is used + if (seq_q_entry.item_priority != -1) begin + if (seq_q_entry.item_priority <= 0) begin + uvm_report_fatal("SEQITEMPRI", + $sformatf("Sequence item from %s has illegal priority: %0d", + seq_q_entry.sequence_ptr.get_full_name(), + seq_q_entry.item_priority), UVM_NONE); + end + return seq_q_entry.item_priority; + end + // Otherwise, use the priority of the calling sequence + if (seq_q_entry.sequence_ptr.get_priority() < 0) begin + uvm_report_fatal("SEQDEFPRI", + $sformatf("Sequence %s has illegal priority: %0d", + seq_q_entry.sequence_ptr.get_full_name(), + seq_q_entry.sequence_ptr.get_priority()), UVM_NONE); + end + return seq_q_entry.sequence_ptr.get_priority(); +endfunction + + +// m_wait_for_arbitration_completed +// -------------------------------- + +task uvm_sequencer_base::m_wait_for_arbitration_completed(int request_id); + int lock_arb_size; + + // Search the list of arb_wait_q, see if this item is done + forever + begin + lock_arb_size = m_lock_arb_size; + + if (arb_completed.exists(request_id)) begin + arb_completed.delete(request_id); + return; + end + wait (lock_arb_size != m_lock_arb_size); + end +endtask + + +// m_set_arbitration_completed +// --------------------------- + +function void uvm_sequencer_base::m_set_arbitration_completed(int request_id); + arb_completed[request_id] = 1; +endfunction + + +// is_child +// -------- + +function bit uvm_sequencer_base::is_child (uvm_sequence_base parent, + uvm_sequence_base child); + uvm_sequence_base child_parent; + + if (child == null) begin + uvm_report_fatal("uvm_sequencer", "is_child passed null child", UVM_NONE); + end + + if (parent == null) begin + uvm_report_fatal("uvm_sequencer", "is_child passed null parent", UVM_NONE); + end + + child_parent = child.get_parent_sequence(); + while (child_parent != null) begin + if (child_parent.get_inst_id() == parent.get_inst_id()) begin + return 1; + end + child_parent = child_parent.get_parent_sequence(); + end + return 0; +endfunction + + +// execute_item +// ------------ + +// Implementation artifact, extends virtual class uvm_sequence_base +// so that it can be constructed for execute_item +class m_uvm_sqr_seq_base extends uvm_sequence_base; + function new(string name="unnamed-m_uvm_sqr_seq_base"); + super.new(name); + endfunction : new +endclass : m_uvm_sqr_seq_base + +task uvm_sequencer_base::execute_item(uvm_sequence_item item); + m_uvm_sqr_seq_base seq; + + seq = new("execute_item_seq"); + item.set_sequencer(this); + item.set_parent_sequence(seq); + seq.set_sequencer(this); + seq.start_item(item); + seq.finish_item(item); +endtask + + +// wait_for_grant +// -------------- + +task uvm_sequencer_base::wait_for_grant(uvm_sequence_base sequence_ptr, + int item_priority = -1, + bit lock_request = 0); + uvm_sequence_request req_s; + int my_seq_id; + + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequencer", + "wait_for_grant passed null sequence_ptr", UVM_NONE); + + my_seq_id = m_register_sequence(sequence_ptr); + + // If lock_request is asserted, then issue a lock. Don't wait for the response, since + // there is a request immediately following the lock request + if (lock_request == 1) begin + req_s = new(); + req_s.grant = 0; + req_s.sequence_id = my_seq_id; + req_s.request = SEQ_TYPE_LOCK; + req_s.sequence_ptr = sequence_ptr; + req_s.request_id = g_request_id++; + req_s.process_id = process::self(); + arb_sequence_q.push_back(req_s); + end + + // Push the request onto the queue + req_s = new(); + req_s.grant = 0; + req_s.request = SEQ_TYPE_REQ; + req_s.sequence_id = my_seq_id; + req_s.item_priority = item_priority; + req_s.sequence_ptr = sequence_ptr; + req_s.request_id = g_request_id++; + req_s.process_id = process::self(); + arb_sequence_q.push_back(req_s); + m_update_lists(); + + // Wait until this entry is granted + // Continue to point to the element, since location in queue will change + m_wait_for_arbitration_completed(req_s.request_id); + + // The wait_for_grant_semaphore is used only to check that send_request + // is only called after wait_for_grant. This is not a complete check, since + // requests might be done in parallel, but it will catch basic errors + req_s.sequence_ptr.m_wait_for_grant_semaphore++; + +endtask + + +// wait_for_item_done +// ------------------ + +task uvm_sequencer_base::wait_for_item_done(uvm_sequence_base sequence_ptr, + int transaction_id); + int sequence_id; + + sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1); + m_wait_for_item_sequence_id = -1; + m_wait_for_item_transaction_id = -1; + + if (transaction_id == -1) + wait (m_wait_for_item_sequence_id == sequence_id); + else + wait ((m_wait_for_item_sequence_id == sequence_id && + m_wait_for_item_transaction_id == transaction_id)); +endtask + + +// is_blocked +// ---------- + +function bit uvm_sequencer_base::is_blocked(uvm_sequence_base sequence_ptr); + + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "is_blocked passed null sequence_ptr", UVM_NONE); + + foreach (lock_list[i]) begin + if ((lock_list[i].get_inst_id() != + sequence_ptr.get_inst_id()) && + (is_child(lock_list[i], sequence_ptr) == 0)) begin + return 1; + end + end + return 0; +endfunction + + +// has_lock +// -------- + +function bit uvm_sequencer_base::has_lock(uvm_sequence_base sequence_ptr); + int my_seq_id; + + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "has_lock passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + foreach (lock_list[i]) begin + if (lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) begin + return 1; + end + end + return 0; +endfunction + + +// m_lock_req +// ---------- +// Internal method. Called by a sequence to request a lock. +// Puts the lock request onto the arbitration queue. + +task uvm_sequencer_base::m_lock_req(uvm_sequence_base sequence_ptr, bit lock); + int my_seq_id; + uvm_sequence_request new_req; + + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "lock_req passed null sequence_ptr", UVM_NONE); + + my_seq_id = m_register_sequence(sequence_ptr); + new_req = new(); + new_req.grant = 0; + new_req.sequence_id = sequence_ptr.get_sequence_id(); + new_req.request = SEQ_TYPE_LOCK; + new_req.sequence_ptr = sequence_ptr; + new_req.request_id = g_request_id++; + new_req.process_id = process::self(); + + if (lock == 1) begin + // Locks are arbitrated just like all other requests + arb_sequence_q.push_back(new_req); + end else begin + // Grabs are not arbitrated - they go to the front + // TODO: + // Missing: grabs get arbitrated behind other grabs + arb_sequence_q.push_front(new_req); + m_update_lists(); + end + + // If this lock can be granted immediately, then do so. + grant_queued_locks(); + + m_wait_for_arbitration_completed(new_req.request_id); +endtask + + +// m_unlock_req +// ------------ +// Called by a sequence to request an unlock. This +// will remove a lock for this sequence if it exists + +function void uvm_sequencer_base::m_unlock_req(uvm_sequence_base sequence_ptr); + if (sequence_ptr == null) begin + uvm_report_fatal("uvm_sequencer", + "m_unlock_req passed null sequence_ptr", UVM_NONE); + end + + begin + int q[$]; + int seqid=sequence_ptr.get_inst_id(); + q=lock_list.find_first_index(item) with (item.get_inst_id() == seqid); + if(q.size()==1) begin + lock_list.delete(q[0]); + grant_queued_locks(); // grant lock requests + m_update_lists(); + end + else + uvm_report_warning("SQRUNL", + {"Sequence '", sequence_ptr.get_full_name(), + "' called ungrab / unlock, but didn't have lock"}, UVM_NONE); + + end +endfunction + + +// lock +// ---- + +task uvm_sequencer_base::lock(uvm_sequence_base sequence_ptr); + m_lock_req(sequence_ptr, 1); +endtask + + +// grab +// ---- + +task uvm_sequencer_base::grab(uvm_sequence_base sequence_ptr); + m_lock_req(sequence_ptr, 0); +endtask + + +// unlock +// ------ + +function void uvm_sequencer_base::unlock(uvm_sequence_base sequence_ptr); + m_unlock_req(sequence_ptr); +endfunction + + +// ungrab +// ------ + +function void uvm_sequencer_base::ungrab(uvm_sequence_base sequence_ptr); + m_unlock_req(sequence_ptr); +endfunction + + +// remove_sequence_from_queues +// --------------------------- + +function void uvm_sequencer_base::remove_sequence_from_queues( + uvm_sequence_base sequence_ptr); + int i; + int seq_id; + + seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0); + + // Remove all queued items for this sequence and any child sequences + i = 0; + do + begin + if (arb_sequence_q.size() > i) begin + if ((arb_sequence_q[i].sequence_id == seq_id) || + (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin + if (sequence_ptr.get_sequence_state() == UVM_FINISHED) + `uvm_error("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before all items from itself and items from descendent sequences are processed. The item request from the sequence '%s' is being removed.", sequence_ptr.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name())) + arb_sequence_q.delete(i); + m_update_lists(); + end + else begin + i++; + end + end + end + while (i < arb_sequence_q.size()); + + // remove locks for this sequence, and any child sequences + i = 0; + do + begin + if (lock_list.size() > i) begin + if ((lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) || + (is_child(sequence_ptr, lock_list[i]))) begin + if (sequence_ptr.get_sequence_state() == UVM_FINISHED) + `uvm_error("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before locks from itself and descedent sequences are removed. The lock held by the child sequence '%s' is being removed.",sequence_ptr.get_full_name(), lock_list[i].get_full_name())) + lock_list.delete(i); + m_update_lists(); + end + else begin + i++; + end + end + end + while (i < lock_list.size()); + + // Unregister the sequence_id, so that any returning data is dropped + m_unregister_sequence(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1)); +endfunction + + +// stop_sequences +// -------------- + +function void uvm_sequencer_base::stop_sequences(); + uvm_sequence_base seq_ptr; + + seq_ptr = m_find_sequence(-1); + while (seq_ptr != null) + begin + kill_sequence(seq_ptr); + seq_ptr = m_find_sequence(-1); + end +endfunction + + +// m_sequence_exiting +// ------------------ + +function void uvm_sequencer_base::m_sequence_exiting(uvm_sequence_base sequence_ptr); + remove_sequence_from_queues(sequence_ptr); +endfunction + + +// kill_sequence +// ------------- + +function void uvm_sequencer_base::kill_sequence(uvm_sequence_base sequence_ptr); + remove_sequence_from_queues(sequence_ptr); + sequence_ptr.m_kill(); +endfunction + + +// is_grabbed +// ---------- + +function bit uvm_sequencer_base::is_grabbed(); + return (lock_list.size() != 0); +endfunction + + +// current_grabber +// --------------- + +function uvm_sequence_base uvm_sequencer_base::current_grabber(); + if (lock_list.size() == 0) begin + return null; + end + return lock_list[lock_list.size()-1]; +endfunction + + +// has_do_available +// ---------------- + +function bit uvm_sequencer_base::has_do_available(); + + foreach (arb_sequence_q[i]) begin + if ((arb_sequence_q[i].sequence_ptr.is_relevant() == 1) && + (is_blocked(arb_sequence_q[i].sequence_ptr) == 0)) begin + return 1; + end + end + return 0; +endfunction + + +// set_arbitration +// --------------- + +function void uvm_sequencer_base::set_arbitration(UVM_SEQ_ARB_TYPE val); + m_arbitration = val; +endfunction + + +// get_arbitration +// --------------- + +function UVM_SEQ_ARB_TYPE uvm_sequencer_base::get_arbitration(); + return m_arbitration; +endfunction + +// get_arbitration_sequence +// --------------- +function uvm_sequence_base uvm_sequencer_base::get_arbitration_sequence( int index); + return arb_sequence_q[index].sequence_ptr; +endfunction + + +// analysis_write +// -------------- + +function void uvm_sequencer_base::analysis_write(uvm_sequence_item t); + return; +endfunction + + +// wait_for_sequences +// ------------------ + +task uvm_sequencer_base::wait_for_sequences(); + uvm_wait_for_nba_region(); +endtask + + + +// send_request +// ------------ + +function void uvm_sequencer_base::send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + return; +endfunction + + +// set_max_zero_time_wait_relevant_count +// ------------ + +function void uvm_sequencer_base::set_max_zero_time_wait_relevant_count(int new_val) ; + m_max_zero_time_wait_relevant_count = new_val ; +endfunction + + +// start_phase_sequence +// -------------------- + +function void uvm_sequencer_base::start_phase_sequence(uvm_phase phase); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_types::rsrc_q_t rq; + uvm_sequence_base seq; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory f = cs.get_factory(); + + // Has a default sequence been specified? + rq = rp.lookup_name({get_full_name(), ".", phase.get_name(), "_phase"}, + "default_sequence", null, 0); + uvm_resource_pool::sort_by_precedence(rq); + + // Look for the first one if the appropriate type + for (int i = 0; seq == null && i < rq.size(); i++) begin + uvm_resource_base rsrc = rq.get(i); + + uvm_resource#(uvm_sequence_base) sbr; + uvm_resource#(uvm_object_wrapper) owr; + + // uvm_config_db#(uvm_sequence_base)? + // Priority is given to uvm_sequence_base because it is a specific sequence instance + // and thus more specific than one that is dynamically created via the + // factory and the object wrapper. + if ($cast(sbr, rsrc) && sbr != null) begin + seq = sbr.read(this); + if (seq == null) begin + `uvm_info("UVM/SQR/PH/DEF/SB/NULL", {"Default phase sequence for phase '", + phase.get_name(),"' explicitly disabled"}, UVM_FULL) + return; + end + end + + // uvm_config_db#(uvm_object_wrapper)? + else if ($cast(owr, rsrc) && owr != null) begin + uvm_object_wrapper wrapper; + + wrapper = owr.read(this); + if (wrapper == null) begin + `uvm_info("UVM/SQR/PH/DEF/OW/NULL", {"Default phase sequence for phase '", + phase.get_name(),"' explicitly disabled"}, UVM_FULL) + return; + end + + if (!$cast(seq, f.create_object_by_type(wrapper, get_full_name(), + wrapper.get_type_name())) + || seq == null) begin + `uvm_warning("PHASESEQ", {"Default sequence for phase '", + phase.get_name(),"' %s is not a sequence type"}) + return; + end + end + end + + if (seq == null) begin + `uvm_info("PHASESEQ", {"No default phase sequence for phase '", + phase.get_name(),"'"}, UVM_FULL) + return; + end + + `uvm_info("PHASESEQ", {"Starting default sequence '", + seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_FULL) + + seq.print_sequence_info = 1; + seq.set_sequencer(this); + seq.reseed(); + seq.set_starting_phase(phase); + + if (seq.get_randomize_enabled() && !seq.randomize()) begin + `uvm_warning("STRDEFSEQ", {"Randomization failed for default sequence '", + seq.get_type_name(),"' for phase '", phase.get_name(),"'"}) + return; + end + + fork begin + uvm_sequence_process_wrapper w = new(); + // reseed this process for random stability + w.pid = process::self(); + w.seq = seq; + w.pid.srandom(uvm_create_random_seed(seq.get_type_name(), this.get_full_name())); + m_default_sequences[phase] = w; + // this will either complete naturally, or be killed later + seq.start(this); + m_default_sequences.delete(phase); + end + join_none + +endfunction + +// stop_phase_sequence +// -------------------- + +function void uvm_sequencer_base::stop_phase_sequence(uvm_phase phase); + if (m_default_sequences.exists(phase)) begin + `uvm_info("PHASESEQ", + {"Killing default sequence '", m_default_sequences[phase].seq.get_type_name(), + "' for phase '", phase.get_name(), "'"}, UVM_FULL) + m_default_sequences[phase].seq.kill(); + end + else begin + `uvm_info("PHASESEQ", + {"No default sequence to kill for phase '", phase.get_name(), "'"}, + UVM_FULL) + end +endfunction : stop_phase_sequence + +//------------------------------------------------------------------------------ +// +// Class- uvm_sequence_request +// +//------------------------------------------------------------------------------ + +class uvm_sequence_request; + bit grant; + int sequence_id; + int request_id; + int item_priority; + process process_id; + uvm_sequencer_base::seq_req_t request; + uvm_sequence_base sequence_ptr; +endclass diff --git a/test_regress/t/t_uvm/seq/uvm_sequencer_param_base.svh b/test_regress/t/t_uvm/seq/uvm_sequencer_param_base.svh new file mode 100644 index 0000000000..c3f756e8b7 --- /dev/null +++ b/test_regress/t/t_uvm/seq/uvm_sequencer_param_base.svh @@ -0,0 +1,464 @@ +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// Copyright 2017 Verific +// 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_sequencer_param_base #(REQ,RSP) +// +// Extends with an API depending on specific +// request (REQ) and response (RSP) types. +//------------------------------------------------------------------------------ + +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif + class uvm_sequencer_param_base #(type REQ = uvm_sequence_item, + type RSP = REQ) extends uvm_sequencer_base; + + typedef uvm_sequencer_param_base #( REQ , RSP) this_type; + typedef REQ req_type; + typedef RSP rsp_type; + + REQ m_last_req_buffer[$]; + RSP m_last_rsp_buffer[$]; + + protected int m_num_last_reqs = 1; + protected int num_last_items = m_num_last_reqs; + protected int m_num_last_rsps = 1; + protected int m_num_reqs_sent; + protected int m_num_rsps_received; + uvm_sequencer_analysis_fifo #(RSP) sqr_rsp_analysis_fifo; + + + // Function -- NODOCS -- new + // + // Creates and initializes an instance of this class using the normal + // constructor arguments for uvm_component: name is the name of the instance, + // and parent is the handle to the hierarchical parent, if any. + // + extern function new (string name, uvm_component parent); + + + // Function -- NODOCS -- send_request + // + // The send_request function may only be called after a wait_for_grant call. + // This call will send the request item, t, to the sequencer pointed to by + // sequence_ptr. The sequencer will forward it to the driver. If rerandomize + // is set, the item will be randomized before being sent to the driver. + // + extern virtual function void send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + + + // Function -- NODOCS -- get_current_item + // + // Returns the request_item currently being executed by the sequencer. If the + // sequencer is not currently executing an item, this method will return ~null~. + // + // The sequencer is executing an item from the time that get_next_item or peek + // is called until the time that get or item_done is called. + // + // Note that a driver that only calls get() will never show a current item, + // since the item is completed at the same time as it is requested. + // + function REQ get_current_item(); + REQ t; + if (m_req_fifo.try_peek(t) == 0) + return null; + return t; + endfunction + + + //---------------- + // Group -- NODOCS -- Requests + //---------------- + + // Function -- NODOCS -- get_num_reqs_sent + // + // Returns the number of requests that have been sent by this sequencer. + // + extern function int get_num_reqs_sent(); + + + // Function -- NODOCS -- set_num_last_reqs + // + // Sets the size of the last_requests buffer. Note that the maximum buffer + // size is 1024. If max is greater than 1024, a warning is issued, and the + // buffer is set to 1024. The default value is 1. + // + extern function void set_num_last_reqs(int unsigned max); + + + // Function -- NODOCS -- get_num_last_reqs + // + // Returns the size of the last requests buffer, as set by set_num_last_reqs. + + extern function int unsigned get_num_last_reqs(); + + + // Function -- NODOCS -- last_req + // + // Returns the last request item by default. If n is not 0, then it will get + // the n�th before last request item. If n is greater than the last request + // buffer size, the function will return ~null~. + // + function REQ last_req(int unsigned n = 0); + if(n > m_num_last_reqs) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last access (%0d), the max history is %0d", n, + m_num_last_reqs)); + return null; + end + if(n == m_last_req_buffer.size()) + return null; + + return m_last_req_buffer[n]; + endfunction + + + + //----------------- + // Group -- NODOCS -- Responses + //----------------- + + // Port -- NODOCS -- rsp_export + // + // Drivers or monitors can connect to this port to send responses + // to the sequencer. Alternatively, a driver can send responses + // via its seq_item_port. + // + //| seq_item_port.item_done(response) + //| seq_item_port.put(response) + //| rsp_port.write(response) <--- via this export + // + // The rsp_port in the driver and/or monitor must be connected to the + // rsp_export in this sequencer in order to send responses through the + // response analysis port. + + uvm_analysis_export #(RSP) rsp_export; + + + // Function -- NODOCS -- get_num_rsps_received + // + // Returns the number of responses received thus far by this sequencer. + + extern function int get_num_rsps_received(); + + + // Function -- NODOCS -- set_num_last_rsps + // + // Sets the size of the last_responses buffer. The maximum buffer size is + // 1024. If max is greater than 1024, a warning is issued, and the buffer is + // set to 1024. The default value is 1. + // + extern function void set_num_last_rsps(int unsigned max); + + + // Function -- NODOCS -- get_num_last_rsps + // + // Returns the max size of the last responses buffer, as set by + // set_num_last_rsps. + // + extern function int unsigned get_num_last_rsps(); + + + // Function -- NODOCS -- last_rsp + // + // Returns the last response item by default. If n is not 0, then it will + // get the nth-before-last response item. If n is greater than the last + // response buffer size, the function will return ~null~. + // + function RSP last_rsp(int unsigned n = 0); + if(n > m_num_last_rsps) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last access (%0d), the max history is %0d", n, + m_num_last_rsps)); + return null; + end + if(n == m_last_rsp_buffer.size()) + return null; + + return m_last_rsp_buffer[n]; + endfunction + + + + // Internal methods and variables; do not use directly, not part of standard + + /* local */ extern function void m_last_rsp_push_front(RSP item); + /* local */ extern function void put_response (RSP t); + /* local */ extern virtual function void build_phase(uvm_phase phase); + /* local */ extern virtual function void connect_phase(uvm_phase phase); + /* local */ extern virtual function void do_print (uvm_printer printer); + /* local */ extern virtual function void analysis_write(uvm_sequence_item t); + /* local */ extern function void m_last_req_push_front(REQ item); + + /* local */ uvm_tlm_fifo #(REQ) m_req_fifo; + +endclass + + +//------------------------------------------------------------------------------ +// IMPLEMENTATION +//------------------------------------------------------------------------------ + +// new +// --- + +function uvm_sequencer_param_base::new (string name, uvm_component parent); + super.new(name, parent); + + rsp_export = new("rsp_export", this); + sqr_rsp_analysis_fifo = new("sqr_rsp_analysis_fifo", this); + sqr_rsp_analysis_fifo.print_enabled = 0; + m_req_fifo = new("req_fifo", this); + m_req_fifo.print_enabled = 0; +endfunction + + +// do_print +// -------- + +function void uvm_sequencer_param_base::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_field_int("num_last_reqs", m_num_last_reqs, $bits(m_num_last_reqs), UVM_DEC); + printer.print_field_int("num_last_rsps", m_num_last_rsps, $bits(m_num_last_rsps), UVM_DEC); +endfunction + + +// connect_phase +// ------------- + +function void uvm_sequencer_param_base::connect_phase(uvm_phase phase); + super.connect_phase(phase); + rsp_export.connect(sqr_rsp_analysis_fifo.analysis_export); +endfunction + + +// build_phase +// ----------- + +function void uvm_sequencer_param_base::build_phase(uvm_phase phase); + super.build_phase(phase); + sqr_rsp_analysis_fifo.sequencer_ptr = this; +endfunction + + +// send_request +// ------------ + +function void uvm_sequencer_param_base::send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + REQ param_t; + + if (sequence_ptr == null) begin + uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE); + end + + if (sequence_ptr.m_wait_for_grant_semaphore < 1) begin + uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE); + end + sequence_ptr.m_wait_for_grant_semaphore--; + + if ($cast(param_t, t)) begin + if (rerandomize == 1) begin + if (!param_t.randomize()) begin + uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request"); + end + end + if (param_t.get_transaction_id() == -1) begin + param_t.set_transaction_id(sequence_ptr.m_next_transaction_id++); + end + m_last_req_push_front(param_t); + end else begin + uvm_report_fatal("SQRSNDREQCAST",$sformatf("send_request failed to cast sequence item"), UVM_NONE); + end + + param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1)); + t.set_sequencer(this); + if (m_req_fifo.try_put(param_t) != 1) begin + uvm_report_fatal("SQRSNDREQGNI", "Concurrent calls to get_next_item() not supported. Consider using a semaphore to ensure that concurrent processes take turns in the driver", UVM_NONE); + end + + m_num_reqs_sent++; + // Grant any locks as soon as possible + grant_queued_locks(); +endfunction + + +// put_response +// ------------ + +function void uvm_sequencer_param_base::put_response (RSP t); + uvm_sequence_base sequence_ptr; + + if (t == null) begin + uvm_report_fatal("SQRPUT", "Driver put a null response", UVM_NONE); + end + + m_last_rsp_push_front(t); + m_num_rsps_received++; + + // Check that set_id_info was called + if (t.get_sequence_id() == -1) begin +`ifndef CDNS_NO_SQR_CHK_SEQ_ID + uvm_report_fatal("SQRPUT", "Driver put a response with null sequence_id", UVM_NONE); +`endif + return; + end + + sequence_ptr = m_find_sequence(t.get_sequence_id()); + + if (sequence_ptr != null) begin + // If the response_handler is enabled for this sequence, then call the response handler + if (sequence_ptr.get_use_response_handler() == 1) begin + sequence_ptr.response_handler(t); + return; + end + + sequence_ptr.put_response(t); + end + else begin + uvm_report_warning("Sequencer", + $sformatf("Dropping response for sequence %0d, sequence not found. Probable cause: sequence exited or has been killed", + t.get_sequence_id())); + end +endfunction + + +// analysis_write +// -------------- + +function void uvm_sequencer_param_base::analysis_write(uvm_sequence_item t); + RSP response; + + if (!$cast(response, t)) begin + uvm_report_fatal("ANALWRT", "Failure to cast analysis port write item", UVM_NONE); + end + put_response(response); +endfunction + + +// get_num_reqs_sent +// ----------------- + +function int uvm_sequencer_param_base::get_num_reqs_sent(); + return m_num_reqs_sent; +endfunction + + +// get_num_rsps_received +// --------------------- + +function int uvm_sequencer_param_base::get_num_rsps_received(); + return m_num_rsps_received; +endfunction + + +// set_num_last_reqs +// ----------------- + +function void uvm_sequencer_param_base::set_num_last_reqs(int unsigned max); + if(max > 1024) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last size; 1024 is the maximum and will be used")); + max = 1024; + end + + //shrink the buffer if necessary + while((m_last_req_buffer.size() != 0) && (m_last_req_buffer.size() > max)) + void'(m_last_req_buffer.pop_back()); + + m_num_last_reqs = max; + num_last_items = max; + +endfunction + + +// get_num_last_reqs +// ----------------- + +function int unsigned uvm_sequencer_param_base::get_num_last_reqs(); + return m_num_last_reqs; +endfunction + + +// m_last_req_push_front +// --------------------- + +function void uvm_sequencer_param_base::m_last_req_push_front(REQ item); + if(!m_num_last_reqs) + return; + + if(m_last_req_buffer.size() == m_num_last_reqs) + void'(m_last_req_buffer.pop_back()); + + this.m_last_req_buffer.push_front(item); +endfunction + + +// set_num_last_rsps +// ----------------- + +function void uvm_sequencer_param_base::set_num_last_rsps(int unsigned max); + if(max > 1024) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last size; 1024 is the maximum and will be used")); + max = 1024; + end + + //shrink the buffer + while((m_last_rsp_buffer.size() != 0) && (m_last_rsp_buffer.size() > max)) begin + void'(m_last_rsp_buffer.pop_back()); + end + + m_num_last_rsps = max; + +endfunction + + +// get_num_last_rsps +// ----------------- + +function int unsigned uvm_sequencer_param_base::get_num_last_rsps(); + return m_num_last_rsps; +endfunction + + +// m_last_rsp_push_front +// --------------------- + +function void uvm_sequencer_param_base::m_last_rsp_push_front(RSP item); + if(!m_num_last_rsps) + return; + + if(m_last_rsp_buffer.size() == m_num_last_rsps) + void'(m_last_rsp_buffer.pop_back()); + + this.m_last_rsp_buffer.push_front(item); +endfunction diff --git a/test_regress/t/t_uvm/tlm1/uvm_analysis_port.svh b/test_regress/t/t_uvm/tlm1/uvm_analysis_port.svh new file mode 100644 index 0000000000..6ce0ac7372 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_analysis_port.svh @@ -0,0 +1,157 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015 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. +//---------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- Analysis Ports +//------------------------------------------------------------------------------ +// +// This section defines the port, export, and imp classes used for transaction +// analysis. +// +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_analysis_port +// +// Broadcasts a value to all subscribers implementing a . +// +//| class mon extends uvm_component; +//| uvm_analysis_port#(trans) ap; +//| +//| function new(string name = "sb", uvm_component parent = null); +//| super.new(name, parent); +//| ap = new("ap", this); +//| endfunction +//| +//| task run_phase(uvm_phase phase); +//| trans t; +//| ... +//| ap.write(t); +//| ... +//| endfunction +//| endclass +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 12.2.10.1.1 +class uvm_analysis_port # (type T = int) + extends uvm_port_base # (uvm_tlm_if_base #(T,T)); + + function new (string name, uvm_component parent); + super.new (name, parent, UVM_PORT, 0, UVM_UNBOUNDED_CONNECTIONS); + m_if_mask = `UVM_TLM_ANALYSIS_MASK; + endfunction + + virtual function string get_type_name(); + return "uvm_analysis_port"; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.2.10.1.2 + function void write (input T t); + uvm_tlm_if_base # (T, T) tif; + for (int i = 0; i < this.size(); i++) begin + tif = this.get_if (i); + if ( tif == null ) + uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE); + tif.write (t); + end + endfunction + +endclass + + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_analysis_imp +// +// Receives all transactions broadcasted by a . It serves as +// the termination point of an analysis port/export/imp connection. The component +// attached to the ~imp~ class--called a ~subscriber~-- implements the analysis +// interface. +// +// Will invoke the ~write(T)~ method in the parent component. +// The implementation of the ~write(T)~ method must not modify +// the value passed to it. +// +//| class sb extends uvm_component; +//| uvm_analysis_imp#(trans, sb) ap; +//| +//| function new(string name = "sb", uvm_component parent = null); +//| super.new(name, parent); +//| ap = new("ap", this); +//| endfunction +//| +//| function void write(trans t); +//| ... +//| endfunction +//| endclass +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 12.2.10.2 +class uvm_analysis_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,"uvm_analysis_imp",IMP) + function void write (input T t); + m_imp.write (t); + endfunction +endclass + + + +//------------------------------------------------------------------------------ +// Class -- NODOCS -- uvm_analysis_export +// +// Exports a lower-level to its parent. +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 12.2.10.3.1 +class uvm_analysis_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + + + // @uvm-ieee 1800.2-2017 auto 12.2.10.3.2 + function new (string name, uvm_component parent = null); + super.new (name, parent, UVM_EXPORT, 1, UVM_UNBOUNDED_CONNECTIONS); + m_if_mask = `UVM_TLM_ANALYSIS_MASK; + endfunction + + virtual function string get_type_name(); + return "uvm_analysis_export"; + endfunction + + // analysis port differs from other ports in that it broadcasts + // to all connected interfaces. Ports only send to the interface + // at the index specified in a call to set_if (0 by default). + function void write (input T t); + uvm_tlm_if_base #(T, T) tif; + for (int i = 0; i < this.size(); i++) begin + tif = this.get_if (i); + if (tif == null) + uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE); + tif.write (t); + end + endfunction + +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_exports.svh b/test_regress/t/t_uvm/tlm1/uvm_exports.svh new file mode 100644 index 0000000000..f4ccf621d0 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_exports.svh @@ -0,0 +1,259 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- UVM TLM Export Classes +//------------------------------------------------------------------------------ +// The following classes define the UVM TLM export classes. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_*_export #(T) +// +// The unidirectional uvm_*_export is a port that ~forwards~ or ~promotes~ +// an interface implementation from a child component to its parent. +// An export can be connected to any compatible child export or imp port. +// It must ultimately be connected to at least one implementation +// of its associated interface. +// +// The interface type represented by the asterisk is any of the following +// +//| blocking_put +//| nonblocking_put +//| put +//| +//| blocking_get +//| nonblocking_get +//| get +//| +//| blocking_peek +//| nonblocking_peek +//| peek +//| +//| blocking_get_peek +//| nonblocking_get_peek +//| get_peek +// +// Type parameters +// +// T - The type of transaction to be communicated by the export +// +// Exports are connected to interface implementations directly via +// ports or indirectly via other exports. +// +//------------------------------------------------------------------------------ + + +// Function -- NODOCS -- new +// +// The ~name~ and ~parent~ are the standard constructor arguments. +// The ~min_size~ and ~max_size~ specify the minimum and maximum number of +// interfaces that must have been supplied to this port by the end of elaboration. +// +//| function new (string name, +//| uvm_component parent, +//| int min_size=1, +//| int max_size=1) + + +class uvm_blocking_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,"uvm_blocking_put_export") + `UVM_BLOCKING_PUT_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_PUT_MASK,"uvm_nonblocking_put_export") + `UVM_NONBLOCKING_PUT_IMP (this.m_if, T, t) +endclass + +class uvm_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_PUT_MASK,"uvm_put_export") + `UVM_PUT_IMP (this.m_if, T, t) +endclass + +class uvm_blocking_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_GET_MASK,"uvm_blocking_get_export") + `UVM_BLOCKING_GET_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_GET_MASK,"uvm_nonblocking_get_export") + `UVM_NONBLOCKING_GET_IMP (this.m_if, T, t) +endclass + +class uvm_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_GET_MASK,"uvm_get_export") + `UVM_GET_IMP (this.m_if, T, t) +endclass + +class uvm_blocking_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_PEEK_MASK,"uvm_blocking_peek_export") + `UVM_BLOCKING_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_PEEK_MASK,"uvm_nonblocking_peek_export") + `UVM_NONBLOCKING_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_PEEK_MASK,"uvm_peek_export") + `UVM_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_blocking_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_GET_PEEK_MASK,"uvm_blocking_get_peek_export") + `UVM_BLOCKING_GET_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_GET_PEEK_MASK,"uvm_nonblocking_get_peek_export") + `UVM_NONBLOCKING_GET_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_EXPORT_COMMON(`UVM_TLM_GET_PEEK_MASK,"uvm_get_peek_export") + `UVM_GET_PEEK_IMP (this.m_if, T, t) +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_*_export #(REQ,RSP) +// +// The bidirectional uvm_*_export is a port that ~forwards~ or ~promotes~ +// an interface implementation from a child component to its parent. +// An export can be connected to any compatible child export or imp port. +// It must ultimately be connected to at least one implementation +// of its associated interface. +// +// The interface type represented by the asterisk is any of the following +// +//| blocking_transport +//| nonblocking_transport +//| transport +//| +//| blocking_master +//| nonblocking_master +//| master +//| +//| blocking_slave +//| nonblocking_slave +//| slave +// +// Type parameters +// +// REQ - The type of request transaction to be communicated by the export +// +// RSP - The type of response transaction to be communicated by the export +// +// Exports are connected to interface implementations directly via +// ports or indirectly via other +// exports. +// +//------------------------------------------------------------------------------ + +// Function -- NODOCS -- new +// +// The ~name~ and ~parent~ are the standard constructor arguments. +// The ~min_size~ and ~max_size~ specify the minimum and maximum number of +// interfaces that must have been supplied to this port by the end of elaboration. +// +//| function new (string name, +//| uvm_component parent, +//| int min_size=1, +//| int max_size=1) + + +class uvm_blocking_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_MASTER_MASK,"uvm_blocking_master_export") + `UVM_BLOCKING_PUT_IMP (this.m_if, REQ, t) + `UVM_BLOCKING_GET_PEEK_IMP (this.m_if, RSP, t) +endclass + +class uvm_nonblocking_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_MASTER_MASK,"uvm_nonblocking_master_export") + `UVM_NONBLOCKING_PUT_IMP (this.m_if, REQ, t) + `UVM_NONBLOCKING_GET_PEEK_IMP (this.m_if, RSP, t) +endclass + +class uvm_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_TLM_MASTER_MASK,"uvm_master_export") + `UVM_PUT_IMP (this.m_if, REQ, t) + `UVM_GET_PEEK_IMP (this.m_if, RSP, t) +endclass + +class uvm_blocking_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_SLAVE_MASK,"uvm_blocking_slave_export") + `UVM_BLOCKING_PUT_IMP (this.m_if, RSP, t) + `UVM_BLOCKING_GET_PEEK_IMP (this.m_if, REQ, t) +endclass + +class uvm_nonblocking_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_SLAVE_MASK,"uvm_nonblocking_slave_export") + `UVM_NONBLOCKING_PUT_IMP (this.m_if, RSP, t) + `UVM_NONBLOCKING_GET_PEEK_IMP (this.m_if, REQ, t) +endclass + +class uvm_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + `UVM_EXPORT_COMMON(`UVM_TLM_SLAVE_MASK,"uvm_slave_export") + `UVM_PUT_IMP (this.m_if, RSP, t) + `UVM_GET_PEEK_IMP (this.m_if, REQ, t) +endclass + +class uvm_blocking_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_TLM_BLOCKING_TRANSPORT_MASK,"uvm_blocking_transport_export") + `UVM_BLOCKING_TRANSPORT_IMP (this.m_if, REQ, RSP, req, rsp) +endclass + +class uvm_nonblocking_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_TLM_NONBLOCKING_TRANSPORT_MASK,"uvm_nonblocking_transport_export") + `UVM_NONBLOCKING_TRANSPORT_IMP (this.m_if, REQ, RSP, req, rsp) +endclass + +class uvm_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_TLM_TRANSPORT_MASK,"uvm_transport_export") + `UVM_TRANSPORT_IMP (this.m_if, REQ, RSP, req, rsp) +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_imps.svh b/test_regress/t/t_uvm/tlm1/uvm_imps.svh new file mode 100644 index 0000000000..873c7f5e06 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_imps.svh @@ -0,0 +1,316 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//-------------.---------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- uvm_*_imp ports +// +// The following defines the UVM TLM implementation (imp) classes. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_*_imp #(T,IMP) +// +// Unidirectional implementation (imp) port classes--An imp port provides access +// to an implementation of the associated interface to all connected ~ports~ and +// ~exports~. Each imp port instance ~must~ be connected to the component instance +// that implements the associated interface, typically the imp port's parent. +// All other connections-- e.g. to other ports and exports-- are prohibited. +// +// The asterisk in ~uvm_*_imp~ may be any of the following +// +//| blocking_put +//| nonblocking_put +//| put +//| +//| blocking_get +//| nonblocking_get +//| get +//| +//| blocking_peek +//| nonblocking_peek +//| peek +//| +//| blocking_get_peek +//| nonblocking_get_peek +//| get_peek +// +// Type parameters +// +// T - The type of transaction to be communicated by the imp +// +// IMP - The type of the component implementing the interface. That is, the class +// to which this imp will delegate. +// +// The interface methods are implemented in a component of type ~IMP~, a handle +// to which is passed in a constructor argument. The imp port delegates all +// interface calls to this component. +// +//------------------------------------------------------------------------------ + + +// Function -- NODOCS -- new +// +// Creates a new unidirectional imp port with the given ~name~ and ~parent~. +// The ~parent~ must implement the interface associated with this port. +// Its type must be the type specified in the imp's type-parameter, ~IMP~. +// +//| function new (string name, IMP parent); + + + +class uvm_blocking_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,"uvm_blocking_put_imp",IMP) + `UVM_BLOCKING_PUT_IMP (m_imp, T, t) +endclass + +class uvm_nonblocking_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_PUT_MASK,"uvm_nonblocking_put_imp",IMP) + `UVM_NONBLOCKING_PUT_IMP (m_imp, T, t) +endclass + +class uvm_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_PUT_MASK,"uvm_put_imp",IMP) + `UVM_PUT_IMP (m_imp, T, t) +endclass + +class uvm_blocking_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_GET_MASK,"uvm_blocking_get_imp",IMP) + `UVM_BLOCKING_GET_IMP (m_imp, T, t) +endclass + +class uvm_nonblocking_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_GET_MASK,"uvm_nonblocking_get_imp",IMP) + `UVM_NONBLOCKING_GET_IMP (m_imp, T, t) +endclass + +class uvm_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_GET_MASK,"uvm_get_imp",IMP) + `UVM_GET_IMP (m_imp, T, t) +endclass + +class uvm_blocking_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_PEEK_MASK,"uvm_blocking_peek_imp",IMP) + `UVM_BLOCKING_PEEK_IMP (m_imp, T, t) +endclass + +class uvm_nonblocking_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_PEEK_MASK,"uvm_nonblocking_peek_imp",IMP) + `UVM_NONBLOCKING_PEEK_IMP (m_imp, T, t) +endclass + +class uvm_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_PEEK_MASK,"uvm_peek_imp",IMP) + `UVM_PEEK_IMP (m_imp, T, t) +endclass + +class uvm_blocking_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_GET_PEEK_MASK,"uvm_blocking_get_peek_imp",IMP) + `UVM_BLOCKING_GET_PEEK_IMP (m_imp, T, t) +endclass + +class uvm_nonblocking_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_GET_PEEK_MASK,"uvm_nonblocking_get_peek_imp",IMP) + `UVM_NONBLOCKING_GET_PEEK_IMP (m_imp, T, t) +endclass + +class uvm_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_IMP_COMMON(`UVM_TLM_GET_PEEK_MASK,"uvm_get_peek_imp",IMP) + `UVM_GET_PEEK_IMP (m_imp, T, t) +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_*_imp #(REQ, RSP, IMP, REQ_IMP, RSP_IMP) +// +// Bidirectional implementation (imp) port classes--An imp port provides access +// to an implementation of the associated interface to all connected ~ports~ and +// ~exports~. Each imp port instance ~must~ be connected to the component instance +// that implements the associated interface, typically the imp port's parent. +// All other connections-- e.g. to other ports and exports-- are prohibited. +// +// The interface represented by the asterisk is any of the following +// +//| blocking_transport +//| nonblocking_transport +//| transport +//| +//| blocking_master +//| nonblocking_master +//| master +//| +//| blocking_slave +//| nonblocking_slave +//| slave +// +// Type parameters +// +// REQ - Request transaction type +// +// RSP - Response transaction type +// +// IMP - Component type that implements the interface methods, typically the +// the parent of this imp port. +// +// REQ_IMP - Component type that implements the request side of the +// interface. Defaults to IMP. For master and slave imps only. +// +// RSP_IMP - Component type that implements the response side of the +// interface. Defaults to IMP. For master and slave imps only. +// +// The interface methods are implemented in a component of type ~IMP~, a handle +// to which is passed in a constructor argument. The imp port delegates all +// interface calls to this component. +// +// The master and slave imps have two modes of operation. +// +// - A single component of type IMP implements the entire interface for +// both requests and responses. +// +// - Two sibling components of type REQ_IMP and RSP_IMP implement the request +// and response interfaces, respectively. In this case, the IMP parent +// instantiates this imp port ~and~ the REQ_IMP and RSP_IMP components. +// +// The second mode is needed when a component instantiates more than one imp +// port, as in the channel. +// +//------------------------------------------------------------------------------ + + +// Function -- NODOCS -- new +// +// Creates a new bidirectional imp port with the given ~name~ and ~parent~. +// The ~parent~, whose type is specified by ~IMP~ type parameter, +// must implement the interface associated with this port. +// +// Transport imp constructor +// +//| function new(string name, IMP imp) +// +// Master and slave imp constructor +// +// The optional ~req_imp~ and ~rsp_imp~ arguments, available to master and +// slave imp ports, allow the requests and responses to be handled by different +// subcomponents. If they are specified, they must point to the underlying +// component that implements the request and response methods, respectively. +// +//| function new(string name, IMP imp, +//| REQ_IMP req_imp=imp, RSP_IMP rsp_imp=imp) + +class uvm_blocking_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + `UVM_MS_IMP_COMMON(`UVM_TLM_BLOCKING_MASTER_MASK,"uvm_blocking_master_imp") + `UVM_BLOCKING_PUT_IMP (m_req_imp, REQ, t) + `UVM_BLOCKING_GET_PEEK_IMP (m_rsp_imp, RSP, t) +endclass + +class uvm_nonblocking_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + `UVM_MS_IMP_COMMON(`UVM_TLM_NONBLOCKING_MASTER_MASK,"uvm_nonblocking_master_imp") + `UVM_NONBLOCKING_PUT_IMP (m_req_imp, REQ, t) + `UVM_NONBLOCKING_GET_PEEK_IMP (m_rsp_imp, RSP, t) +endclass + +class uvm_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + `UVM_MS_IMP_COMMON(`UVM_TLM_MASTER_MASK,"uvm_master_imp") + `UVM_PUT_IMP (m_req_imp, REQ, t) + `UVM_GET_PEEK_IMP (m_rsp_imp, RSP, t) +endclass + +class uvm_blocking_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + `UVM_MS_IMP_COMMON(`UVM_TLM_BLOCKING_SLAVE_MASK,"uvm_blocking_slave_imp") + `UVM_BLOCKING_PUT_IMP (m_rsp_imp, RSP, t) + `UVM_BLOCKING_GET_PEEK_IMP (m_req_imp, REQ, t) +endclass + +class uvm_nonblocking_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + `UVM_MS_IMP_COMMON(`UVM_TLM_NONBLOCKING_SLAVE_MASK,"uvm_nonblocking_slave_imp") + `UVM_NONBLOCKING_PUT_IMP (m_rsp_imp, RSP, t) + `UVM_NONBLOCKING_GET_PEEK_IMP (m_req_imp, REQ, t) +endclass + +class uvm_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + `UVM_MS_IMP_COMMON(`UVM_TLM_SLAVE_MASK,"uvm_slave_imp") + `UVM_PUT_IMP (m_rsp_imp, RSP, t) + `UVM_GET_PEEK_IMP (m_req_imp, REQ, t) +endclass + +class uvm_blocking_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_IMP_COMMON(`UVM_TLM_BLOCKING_TRANSPORT_MASK,"uvm_blocking_transport_imp",IMP) + `UVM_BLOCKING_TRANSPORT_IMP (m_imp, REQ, RSP, req, rsp) +endclass + +class uvm_nonblocking_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_IMP_COMMON(`UVM_TLM_NONBLOCKING_TRANSPORT_MASK,"uvm_nonblocking_transport_imp",IMP) + `UVM_NONBLOCKING_TRANSPORT_IMP (m_imp, REQ, RSP, req, rsp) +endclass + +class uvm_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_IMP_COMMON(`UVM_TLM_TRANSPORT_MASK,"uvm_transport_imp",IMP) + `UVM_BLOCKING_TRANSPORT_IMP (m_imp, REQ, RSP, req, rsp) + `UVM_NONBLOCKING_TRANSPORT_IMP (m_imp, REQ, RSP, req, rsp) +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_ports.svh b/test_regress/t/t_uvm/tlm1/uvm_ports.svh new file mode 100644 index 0000000000..88e59187c6 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_ports.svh @@ -0,0 +1,262 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//---------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- UVM TLM Port Classes +//------------------------------------------------------------------------------ +// The following classes define the UVM TLM port classes. +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_*_port #(T) +// +// These unidirectional ports are instantiated by components that ~require~, +// or ~use~, the associated interface to convey transactions. A port can +// be connected to any compatible port, export, or imp port. Unless its +// ~min_size~ is 0, a port ~must~ be connected to at least one implementation +// of its associated interface. +// +// The asterisk in ~uvm_*_port~ is any of the following +// +//| blocking_put +//| nonblocking_put +//| put +//| +//| blocking_get +//| nonblocking_get +//| get +//| +//| blocking_peek +//| nonblocking_peek +//| peek +//| +//| blocking_get_peek +//| nonblocking_get_peek +//| get_peek +// +// Type parameters +// +// T - The type of transaction to be communicated by the export. The type T is not restricted +// to class handles and may be a value type such as int,enum,struct or similar. +// +// Ports are connected to interface implementations directly via +// ports or indirectly via hierarchical connections +// to and ports. +// +//------------------------------------------------------------------------------ + + +// Function -- NODOCS -- new +// +// The ~name~ and ~parent~ are the standard constructor arguments. +// The ~min_size~ and ~max_size~ specify the minimum and maximum number of +// interfaces that must have been connected to this port by the end of elaboration. +// +//| function new (string name, +//| uvm_component parent, +//| int min_size=1, +//| int max_size=1) + +class uvm_blocking_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_PUT_MASK,"uvm_blocking_put_port") + `UVM_BLOCKING_PUT_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_PUT_MASK,"uvm_nonblocking_put_port") + `UVM_NONBLOCKING_PUT_IMP (this.m_if, T, t) +endclass + +class uvm_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_PUT_MASK,"uvm_put_port") + `UVM_PUT_IMP (this.m_if, T, t) +endclass + +class uvm_blocking_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_GET_MASK,"uvm_blocking_get_port") + `UVM_BLOCKING_GET_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_GET_MASK,"uvm_nonblocking_get_port") + `UVM_NONBLOCKING_GET_IMP (this.m_if, T, t) +endclass + +class uvm_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_GET_MASK,"uvm_get_port") + `UVM_GET_IMP (this.m_if, T, t) +endclass + +class uvm_blocking_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_PEEK_MASK,"uvm_blocking_peek_port") + `UVM_BLOCKING_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_PEEK_MASK,"uvm_nonblocking_peek_port") + `UVM_NONBLOCKING_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_PEEK_MASK,"uvm_peek_port") + `UVM_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_blocking_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_GET_PEEK_MASK,"uvm_blocking_get_peek_port") + `UVM_BLOCKING_GET_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_nonblocking_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_GET_PEEK_MASK,"uvm_nonblocking_get_peek_port") + `UVM_NONBLOCKING_GET_PEEK_IMP (this.m_if, T, t) +endclass + +class uvm_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + `UVM_PORT_COMMON(`UVM_TLM_GET_PEEK_MASK,"uvm_get_peek_port") + `UVM_GET_PEEK_IMP (this.m_if, T, t) +endclass + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_*_port #(REQ,RSP) +// +// These bidirectional ports are instantiated by components that ~require~, +// or ~use~, the associated interface to convey transactions. A port can +// be connected to any compatible port, export, or imp port. Unless its +// ~min_size~ is 0, a port ~must~ be connected to at least one implementation +// of its associated interface. +// +// The asterisk in ~uvm_*_port~ is any of the following +// +//| blocking_transport +//| nonblocking_transport +//| transport +//| +//| blocking_master +//| nonblocking_master +//| master +//| +//| blocking_slave +//| nonblocking_slave +//| slave +// +// Ports are connected to interface implementations directly via +// ports or indirectly via +// hierarchical connections to and +// ports. +// +// Type parameters +// +// REQ - The type of request transaction to be communicated by the export +// +// RSP - The type of response transaction to be communicated by the export +// +//------------------------------------------------------------------------------ + +// Function -- NODOCS -- new +// +// The ~name~ and ~parent~ are the standard constructor arguments. +// The ~min_size~ and ~max_size~ specify the minimum and maximum number of +// interfaces that must have been supplied to this port by the end of elaboration. +// +// function new (string name, +// uvm_component parent, +// int min_size=1, +// int max_size=1) + + +class uvm_blocking_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_MASTER_MASK,"uvm_blocking_master_port") + `UVM_BLOCKING_PUT_IMP (this.m_if, REQ, t) + `UVM_BLOCKING_GET_PEEK_IMP (this.m_if, RSP, t) +endclass + +class uvm_nonblocking_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_MASTER_MASK,"uvm_nonblocking_master_port") + `UVM_NONBLOCKING_PUT_IMP (this.m_if, REQ, t) + `UVM_NONBLOCKING_GET_PEEK_IMP (this.m_if, RSP, t) +endclass + +class uvm_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_PORT_COMMON(`UVM_TLM_MASTER_MASK,"uvm_master_port") + `UVM_PUT_IMP (this.m_if, REQ, t) + `UVM_GET_PEEK_IMP (this.m_if, RSP, t) +endclass + +class uvm_blocking_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_SLAVE_MASK,"uvm_blocking_slave_port") + `UVM_BLOCKING_PUT_IMP (this.m_if, RSP, t) + `UVM_BLOCKING_GET_PEEK_IMP (this.m_if, REQ, t) +endclass + +class uvm_nonblocking_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_SLAVE_MASK,"uvm_nonblocking_slave_port") + `UVM_NONBLOCKING_PUT_IMP (this.m_if, RSP, t) + `UVM_NONBLOCKING_GET_PEEK_IMP (this.m_if, REQ, t) +endclass + +class uvm_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + `UVM_PORT_COMMON(`UVM_TLM_SLAVE_MASK,"uvm_slave_port") + `UVM_PUT_IMP (this.m_if, RSP, t) + `UVM_GET_PEEK_IMP (this.m_if, REQ, t) +endclass + +class uvm_blocking_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_PORT_COMMON(`UVM_TLM_BLOCKING_TRANSPORT_MASK,"uvm_blocking_transport_port") + `UVM_BLOCKING_TRANSPORT_IMP (this.m_if, REQ, RSP, req, rsp) +endclass + +class uvm_nonblocking_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_PORT_COMMON(`UVM_TLM_NONBLOCKING_TRANSPORT_MASK,"uvm_nonblocking_transport_port") + `UVM_NONBLOCKING_TRANSPORT_IMP (this.m_if, REQ, RSP, req, rsp) +endclass + +class uvm_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + `UVM_PORT_COMMON(`UVM_TLM_TRANSPORT_MASK,"uvm_transport_port") + `UVM_TRANSPORT_IMP (this.m_if, REQ, RSP, req, rsp) +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_sqr_connections.svh b/test_regress/t/t_uvm/tlm1/uvm_sqr_connections.svh new file mode 100644 index 0000000000..f7890b3a76 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_sqr_connections.svh @@ -0,0 +1,89 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2015-2018 NVIDIA Corporation +// Copyright 2012 Accellera Systems Initiative +// 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. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Title -- NODOCS -- Sequence Item Pull Ports +// +// This section defines the port, export, and imp port classes for +// communicating sequence items between and +// . +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// Class -- NODOCS -- uvm_seq_item_pull_port #(REQ,RSP) +// +// UVM provides a port, export, and imp connector for use in sequencer-driver +// communication. All have standard port connector constructors, except that +// uvm_seq_item_pull_port's default min_size argument is 0; it can be left +// unconnected. +// +//----------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 15.2.2.1 +class uvm_seq_item_pull_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + `UVM_SEQ_PORT(`UVM_SEQ_ITEM_PULL_MASK, "uvm_seq_item_pull_port") + `UVM_SEQ_ITEM_PULL_IMP(this.m_if, REQ, RSP, t, t) + + bit print_enabled; + +endclass + + +//----------------------------------------------------------------------------- +// +// Class -- NODOCS -- uvm_seq_item_pull_export #(REQ,RSP) +// +// This export type is used in sequencer-driver communication. It has the +// standard constructor for exports. +// +//----------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 15.2.2.2 +class uvm_seq_item_pull_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + `UVM_EXPORT_COMMON(`UVM_SEQ_ITEM_PULL_MASK, "uvm_seq_item_pull_export") + `UVM_SEQ_ITEM_PULL_IMP(this.m_if, REQ, RSP, t, t) +endclass + + +//----------------------------------------------------------------------------- +// +// Class -- NODOCS -- uvm_seq_item_pull_imp #(REQ,RSP,IMP) +// +// This imp type is used in sequencer-driver communication. It has the +// standard constructor for imp-type ports. +// +//----------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 15.2.2.3 +class uvm_seq_item_pull_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + // Function -- NODOCS -- new + `UVM_IMP_COMMON(`UVM_SEQ_ITEM_PULL_MASK, "uvm_seq_item_pull_imp",IMP) + `UVM_SEQ_ITEM_PULL_IMP(m_imp, REQ, RSP, t, t) + +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_sqr_ifs.svh b/test_regress/t/t_uvm/tlm1/uvm_sqr_ifs.svh new file mode 100644 index 0000000000..e36c8e116c --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_sqr_ifs.svh @@ -0,0 +1,267 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2013 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2011 AMD +// Copyright 2013-2015 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +//------------------------------------------------------------------------------ + + +`define UVM_SEQ_ITEM_TASK_ERROR "Sequencer interface task not implemented" +`define UVM_SEQ_ITEM_FUNCTION_ERROR "Sequencer interface function not implemented" + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_sqr_if_base #(REQ,RSP) +// +// This class defines an interface for sequence drivers to communicate with +// sequencers. The driver requires the interface via a port, and the sequencer +// implements it and provides it via an export. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 15.2.1.1 +virtual class uvm_sqr_if_base #(type T1=uvm_object, T2=T1); + + // Task -- NODOCS -- get_next_item + // + // Retrieves the next available item from a sequence. The call will block + // until an item is available. The following steps occur on this call: + // + // 1 - Arbitrate among requesting, unlocked, relevant sequences - choose the + // highest priority sequence based on the current sequencer arbitration + // mode. If no sequence is available, wait for a requesting unlocked + // relevant sequence, then re-arbitrate. + // 2 - The chosen sequence will return from wait_for_grant + // 3 - The chosen sequence is called + // 4 - The chosen sequence item is randomized + // 5 - The chosen sequence is called + // 6 - Return with a reference to the item + // + // Once is called, must be called to indicate the + // completion of the request to the sequencer. This will remove the request + // item from the sequencer FIFO. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.1 + virtual task get_next_item(output T1 t); + uvm_report_error("get_next_item", `UVM_SEQ_ITEM_TASK_ERROR, UVM_NONE); + endtask + + + // Task -- NODOCS -- try_next_item + // + // Retrieves the next available item from a sequence if one is available. + // Otherwise, the function returns immediately with request set to ~null~. + // The following steps occur on this call: + // + // 1 - Arbitrate among requesting, unlocked, relevant sequences - choose the + // highest priority sequence based on the current sequencer arbitration + // mode. If no sequence is available, return ~null~. + // 2 - The chosen sequence will return from wait_for_grant + // 3 - The chosen sequence is called + // 4 - The chosen sequence item is randomized + // 5 - The chosen sequence is called + // 6 - Return with a reference to the item + // + // Once is called, must be called to indicate the + // completion of the request to the sequencer. This will remove the request + // item from the sequencer FIFO. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.2 + virtual task try_next_item(output T1 t); + uvm_report_error("try_next_item", `UVM_SEQ_ITEM_TASK_ERROR, UVM_NONE); + endtask + + + // Function -- NODOCS -- item_done + // + // Indicates that the request is completed to the sequencer. Any + // + // calls made by a sequence for this item will return. + // + // The current item is removed from the sequencer FIFO. + // + // If a response item is provided, then it will be sent back to the requesting + // sequence. The response item must have its sequence ID and transaction ID + // set correctly, using the method: + // + //| rsp.set_id_info(req); + // + // Before is called, any calls to peek will retrieve the current + // item that was obtained by . After is called, peek + // will cause the sequencer to arbitrate for a new item. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.3 + virtual function void item_done(input T2 t = null); + uvm_report_error("item_done", `UVM_SEQ_ITEM_FUNCTION_ERROR, UVM_NONE); + endfunction + + + // Task -- NODOCS -- wait_for_sequences + // + // Waits for a sequence to have a new item available. The default + // implementation in the sequencer calls + // . + // User-derived sequencers + // may override its implementation to perform some other + // application-specific implementation. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.4 + virtual task wait_for_sequences(); + uvm_report_error("wait_for_sequences", `UVM_SEQ_ITEM_TASK_ERROR, UVM_NONE); + endtask + + + // Function -- NODOCS -- has_do_available + // + // Indicates whether a sequence item is available for immediate processing. + // Implementations should return 1 if an item is available, 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.5 + virtual function bit has_do_available(); + uvm_report_error("has_do_available", `UVM_SEQ_ITEM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + //----------------------- + // uvm_tlm_blocking_slave_if + //----------------------- + + // Task -- NODOCS -- get + // + // Retrieves the next available item from a sequence. The call blocks until + // an item is available. The following steps occur on this call: + // + // 1 - Arbitrate among requesting, unlocked, relevant sequences - choose the + // highest priority sequence based on the current sequencer arbitration + // mode. If no sequence is available, wait for a requesting unlocked + // relevant sequence, then re-arbitrate. + // 2 - The chosen sequence will return from + // 3 - The chosen sequence is called + // 4 - The chosen sequence item is randomized + // 5 - The chosen sequence is called + // 6 - Indicate to the sequencer + // 7 - Return with a reference to the item + // + // When get is called, may not be called. A new item can be + // obtained by calling get again, or a response may be sent using either + // , or uvm_driver::rsp_port.write(). + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.6 + virtual task get(output T1 t); + uvm_report_error("get", `UVM_SEQ_ITEM_TASK_ERROR, UVM_NONE); + endtask + + // Task -- NODOCS -- peek + // + // Returns the current request item if one is in the sequencer FIFO. If no + // item is in the FIFO, then the call will block until the sequencer has a new + // request. The following steps will occur if the sequencer FIFO is empty: + // + // 1 - Arbitrate among requesting, unlocked, relevant sequences - choose the + // highest priority sequence based on the current sequencer arbitration mode. + // If no sequence is available, wait for a requesting unlocked relevant + // sequence, then re-arbitrate. + // + // 2 - The chosen sequence will return from + // 3 - The chosen sequence is called + // 4 - The chosen sequence item is randomized + // 5 - The chosen sequence is called + // + // Once a request item has been retrieved and is in the sequencer FIFO, + // subsequent calls to peek will return the same item. The item will stay in + // the FIFO until either get or is called. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.7 + virtual task peek(output T1 t); + uvm_report_error("peek", `UVM_SEQ_ITEM_TASK_ERROR, UVM_NONE); + endtask + + + // Task -- NODOCS -- put + // + // Sends a response back to the sequence that issued the request. Before the + // response is put, it must have its sequence ID and transaction ID set to + // match the request. This can be done using the + // call: + // + // rsp.set_id_info(req); + // + // While this is a task, it will not consume time (including delta cycles). + // The response will be put into the + // sequence response queue or it will be sent to the + // sequence response handler. + // + + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.8 + virtual task put(input T2 t); + uvm_report_error("put", `UVM_SEQ_ITEM_TASK_ERROR, UVM_NONE); + endtask + + + // Function -- NODOCS -- put_response + // + // Sends a response back to the sequence that issued the request. Before the + // response is put, it must have its sequence ID and transaction ID set to + // match the request. This can be done using the + // call: + // + // rsp.set_id_info(req); + // + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.9 + virtual function void put_response(input T2 t); + uvm_report_error("put_response", `UVM_SEQ_ITEM_FUNCTION_ERROR, UVM_NONE); + endfunction + + // Function -- NODOCS -- disable_auto_item_recording + // + // By default, item recording is performed automatically when + // get_next_item() and item_done() are called. + // However, this works only for simple, in-order, blocking transaction + // execution. For pipelined and out-of-order transaction execution, the + // driver must turn off this automatic recording and call + // , + // and explicitly at appropriate points in time. + // + // This methods be called at the beginning of the driver's ~run_phase()~ method. + // Once disabled, automatic recording cannot be re-enabled. + // + // For backward-compatibility, automatic item recording can be globally + // turned off at compile time by defining UVM_DISABLE_AUTO_ITEM_RECORDING + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.10 + virtual function void disable_auto_item_recording(); + uvm_report_error("disable_auto_item_recording", `UVM_SEQ_ITEM_FUNCTION_ERROR, UVM_NONE); + endfunction + + // Function -- NODOCS -- is_auto_item_recording_enabled + // + // Return TRUE if automatic item recording is enabled for this port instance. + + // @uvm-ieee 1800.2-2017 auto 15.2.1.2.11 + virtual function bit is_auto_item_recording_enabled(); + uvm_report_error("is_auto_item_recording_enabled", `UVM_SEQ_ITEM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_tlm.svh b/test_regress/t/t_uvm/tlm1/uvm_tlm.svh new file mode 100644 index 0000000000..d627ec43b1 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_tlm.svh @@ -0,0 +1,39 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// 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. +//---------------------------------------------------------------------- + +`include "tlm1/uvm_tlm_ifs.svh" +`include "tlm1/uvm_sqr_ifs.svh" +`include "base/uvm_port_base.svh" + +`include "tlm1/uvm_tlm_imps.svh" + +`include "tlm1/uvm_imps.svh" +`include "tlm1/uvm_ports.svh" +`include "tlm1/uvm_exports.svh" +`include "tlm1/uvm_analysis_port.svh" + +`include "tlm1/uvm_tlm_fifo_base.svh" +`include "tlm1/uvm_tlm_fifos.svh" +`include "tlm1/uvm_tlm_req_rsp.svh" + +`include "tlm1/uvm_sqr_connections.svh" diff --git a/test_regress/t/t_uvm/tlm1/uvm_tlm_fifo_base.svh b/test_regress/t/t_uvm/tlm1/uvm_tlm_fifo_base.svh new file mode 100644 index 0000000000..0fc07afb76 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_tlm_fifo_base.svh @@ -0,0 +1,273 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2014-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//------------------------------------------------------------------------------ + +`define UVM_TLM_FIFO_TASK_ERROR "fifo channel task not implemented" +`define UVM_TLM_FIFO_FUNCTION_ERROR "fifo channel function not implemented" + +class uvm_tlm_event; + event trigger; +endclass + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_tlm_fifo_base #(T) +// +// This class is the base for . It defines the UVM TLM exports +// through which all transaction-based FIFO operations occur. It also defines +// default implementations for each interface method provided by these exports. +// +// The interface methods provided by the and the +// are defined and described by . See the UVM TLM Overview +// section 12.1 for a general discussion of UVM TLM interface definition and usage. +// +// Parameter type +// +// T - The type of transactions to be stored by this FIFO. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 12.2.8.1.1 +virtual class uvm_tlm_fifo_base #(type T=int) extends uvm_component; + + `uvm_component_abstract_param_utils(uvm_tlm_fifo_base #(T)) + + typedef uvm_tlm_fifo_base #(T) this_type; + + // Port -- NODOCS -- put_export + // + // The ~put_export~ provides both the blocking and non-blocking put interface + // methods to any attached port: + // + //| task put (input T t) + //| function bit can_put () + //| function bit try_put (input T t) + // + // Any ~put~ port variant can connect and send transactions to the FIFO via this + // export, provided the transaction types match. See + // for more information on each of the above interface methods. + + uvm_put_imp #(T, this_type) put_export; + + + // Port -- NODOCS -- get_peek_export + // + // The ~get_peek_export~ provides all the blocking and non-blocking get and peek + // interface methods: + // + //| task get (output T t) + //| function bit can_get () + //| function bit try_get (output T t) + //| task peek (output T t) + //| function bit can_peek () + //| function bit try_peek (output T t) + // + // Any ~get~ or ~peek~ port variant can connect to and retrieve transactions from + // the FIFO via this export, provided the transaction types match. See + // for more information on each of the above interface + // methods. + + uvm_get_peek_imp #(T, this_type) get_peek_export; + + + // Port -- NODOCS -- put_ap + // + // Transactions passed via ~put~ or ~try_put~ (via any port connected to the + // ) are sent out this port via its ~write~ method. + // + //| function void write (T t) + // + // All connected analysis exports and imps will receive put transactions. + // See for more information on the ~write~ interface + // method. + + uvm_analysis_port #(T) put_ap; + + + // Port -- NODOCS -- get_ap + // + // Transactions passed via ~get~, ~try_get~, ~peek~, or ~try_peek~ (via any + // port connected to the ) are sent out this port via its + // ~write~ method. + // + //| function void write (T t) + // + // All connected analysis exports and imps will receive get transactions. + // See for more information on the ~write~ method. + + uvm_analysis_port #(T) get_ap; + + + // The following are aliases to the above put_export. + + uvm_put_imp #(T, this_type) blocking_put_export; + uvm_put_imp #(T, this_type) nonblocking_put_export; + + // The following are all aliased to the above get_peek_export, which provides + // the superset of these interfaces. + + uvm_get_peek_imp #(T, this_type) blocking_get_export; + uvm_get_peek_imp #(T, this_type) nonblocking_get_export; + uvm_get_peek_imp #(T, this_type) get_export; + + uvm_get_peek_imp #(T, this_type) blocking_peek_export; + uvm_get_peek_imp #(T, this_type) nonblocking_peek_export; + uvm_get_peek_imp #(T, this_type) peek_export; + + uvm_get_peek_imp #(T, this_type) blocking_get_peek_export; + uvm_get_peek_imp #(T, this_type) nonblocking_get_peek_export; + + + // Function -- NODOCS -- new + // + // The ~name~ and ~parent~ are the normal uvm_component constructor arguments. + // The ~parent~ should be ~null~ if the uvm_tlm_fifo is going to be used in a + // statically elaborated construct (e.g., a module). The ~size~ indicates the + // maximum size of the FIFO. A value of zero indicates no upper bound. + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.7 + // @uvm-ieee 1800.2-2017 auto 12.2.8.2.1 + // @uvm-ieee 1800.2-2017 auto 12.2.8.3.2 + function new(string name, uvm_component parent = null); + super.new(name, parent); + + put_export = new("put_export", this); + blocking_put_export = put_export; + nonblocking_put_export = put_export; + + get_peek_export = new("get_peek_export", this); + blocking_get_peek_export = get_peek_export; + nonblocking_get_peek_export = get_peek_export; + blocking_get_export = get_peek_export; + nonblocking_get_export = get_peek_export; + get_export = get_peek_export; + blocking_peek_export = get_peek_export; + nonblocking_peek_export = get_peek_export; + peek_export = get_peek_export; + + put_ap = new("put_ap", this); + get_ap = new("get_ap", this); + + endfunction + + //turn off auto config + virtual function bit use_automatic_config(); + return 0; + endfunction : use_automatic_config + + // @uvm-ieee 1800.2-2017 auto 12.2.8.2.6 + virtual function void flush(); + uvm_report_error("flush", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.2.2 + virtual function int size(); + uvm_report_error("size", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.3 + virtual task put(T t); + uvm_report_error("put", `UVM_TLM_FIFO_TASK_ERROR, UVM_NONE); + endtask + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.4 + virtual task get(output T t); + uvm_report_error("get", `UVM_TLM_FIFO_TASK_ERROR, UVM_NONE); + endtask + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.4 + virtual task peek(output T t); + uvm_report_error("peek", `UVM_TLM_FIFO_TASK_ERROR, UVM_NONE); + endtask + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.3 + virtual function bit try_put(T t); + uvm_report_error("try_put", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.4 + virtual function bit try_get(output T t); + uvm_report_error("try_get", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.4 + virtual function bit try_peek(output T t); + uvm_report_error("try_peek", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.3 + virtual function bit can_put(); + uvm_report_error("can_put", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.4 + virtual function bit can_get(); + uvm_report_error("can_get", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.1.4 + virtual function bit can_peek(); + uvm_report_error("can_peek", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + virtual function uvm_tlm_event ok_to_put(); + uvm_report_error("ok_to_put", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return null; + endfunction + + virtual function uvm_tlm_event ok_to_get(); + uvm_report_error("ok_to_get", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return null; + endfunction + + virtual function uvm_tlm_event ok_to_peek(); + uvm_report_error("ok_to_peek", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return null; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.2.4 + virtual function bit is_empty(); + uvm_report_error("is_empty", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.2.5 + virtual function bit is_full(); + uvm_report_error("is_full", `UVM_TLM_FIFO_FUNCTION_ERROR); + return 0; + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.8.2.3 + virtual function int used(); + uvm_report_error("used", `UVM_TLM_FIFO_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_tlm_fifos.svh b/test_regress/t/t_uvm/tlm1/uvm_tlm_fifos.svh new file mode 100644 index 0000000000..86ca938512 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_tlm_fifos.svh @@ -0,0 +1,233 @@ +// +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//------------------------------------------------------------------------------ + +typedef class uvm_tlm_event; + +//------------------------------------------------------------------------------ +// +// Title -- NODOCS -- UVM TLM FIFO Classes +// +// This section defines TLM-based FIFO classes. +// +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_tlm_fifo#(T) +// +// This class provides storage of transactions between two independently running +// processes. Transactions are put into the FIFO via the ~put_export~. +// transactions are fetched from the FIFO in the order they arrived via the +// ~get_peek_export~. The ~put_export~ and ~get_peek_export~ are inherited from +// the super class, and the interface methods provided by +// these exports are defined by the class. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 18.2.8.2 +class uvm_tlm_fifo #(type T=int) extends uvm_tlm_fifo_base #(T); + + `uvm_component_param_utils(uvm_tlm_fifo#(T)) + `uvm_type_name_decl("uvm_tlm_fifo #(T)") + + local mailbox #( T ) m; + local int m_size; + protected int m_pending_blocked_gets; + + + // Function -- NODOCS -- new + // + // The ~name~ and ~parent~ are the normal uvm_component constructor arguments. + // The ~parent~ should be ~null~ if the is going to be used in a + // statically elaborated construct (e.g., a module). The ~size~ indicates the + // maximum size of the FIFO; a value of zero indicates no upper bound. + + function new(string name, uvm_component parent = null, int size = 1); + super.new(name, parent); + m = new( size ); + m_size = size; + endfunction + + // Function -- NODOCS -- size + // + // Returns the capacity of the FIFO-- that is, the number of entries + // the FIFO is capable of holding. A return value of 0 indicates the + // FIFO capacity has no limit. + + virtual function int size(); + return m_size; + endfunction + + + // Function -- NODOCS -- used + // + // Returns the number of entries put into the FIFO. + + virtual function int used(); + return m.num(); + endfunction + + + // Function -- NODOCS -- is_empty + // + // Returns 1 when there are no entries in the FIFO, 0 otherwise. + + virtual function bit is_empty(); + return (m.num() == 0); + endfunction + + + // Function -- NODOCS -- is_full + // + // Returns 1 when the number of entries in the FIFO is equal to its , + // 0 otherwise. + + virtual function bit is_full(); + return (m_size != 0) && (m.num() == m_size); + endfunction + + + + virtual task put( input T t ); + m.put( t ); + put_ap.write( t ); + endtask + + virtual task get( output T t ); + m_pending_blocked_gets++; + m.get( t ); + m_pending_blocked_gets--; + get_ap.write( t ); + endtask + + virtual task peek( output T t ); + m.peek( t ); + endtask + + virtual function bit try_get( output T t ); + if( !m.try_get( t ) ) begin + return 0; + end + + get_ap.write( t ); + return 1; + endfunction + + virtual function bit try_peek( output T t ); + if( !m.try_peek( t ) ) begin + return 0; + end + return 1; + endfunction + + virtual function bit try_put( input T t ); + if( !m.try_put( t ) ) begin + return 0; + end + + put_ap.write( t ); + return 1; + endfunction + + virtual function bit can_put(); + return m_size == 0 || m.num() < m_size; + endfunction + + virtual function bit can_get(); + return m.num() > 0 && m_pending_blocked_gets == 0; + endfunction + + virtual function bit can_peek(); + return m.num() > 0; + endfunction + + + // Function -- NODOCS -- flush + // + // Removes all entries from the FIFO, after which returns 0 + // and returns 1. + + virtual function void flush(); + T t; + bit r; + + r = 1; + while( r ) r = try_get( t ) ; + + if( m.num() > 0 && m_pending_blocked_gets != 0 ) begin + uvm_report_error("flush failed" , + "there are blocked gets preventing the flush", UVM_NONE); + end + + endfunction + +endclass + + +//------------------------------------------------------------------------------ +// +// Class -- NODOCS -- uvm_tlm_analysis_fifo#(T) +// +// An analysis_fifo is a with an unbounded size and a write interface. +// It can be used any place a is used. Typical usage is +// as a buffer between a in an initiator component +// and TLM1 target component. +// +//------------------------------------------------------------------------------ + +class uvm_tlm_analysis_fifo #(type T = int) extends uvm_tlm_fifo #(T); + `uvm_component_param_utils(uvm_tlm_analysis_fifo#(T)) + `uvm_type_name_decl("uvm_tlm_analysis_fifo #(T)") + + // Port -- NODOCS -- analysis_export #(T) + // + // The analysis_export provides the write method to all connected analysis + // ports and parent exports: + // + //| function void write (T t) + // + // Access via ports bound to this export is the normal mechanism for writing + // to an analysis FIFO. + // See write method of for more information. + + uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export; + + + // Function -- NODOCS -- new + // + // This is the standard uvm_component constructor. ~name~ is the local name + // of this component. The ~parent~ should be left unspecified when this + // component is instantiated in statically elaborated constructs and must be + // specified when this component is a child of another UVM component. + + function new(string name , uvm_component parent = null); + super.new(name, parent, 0); // analysis fifo must be unbounded + analysis_export = new("analysis_export", this); + endfunction + + function void write(input T t); + void'(this.try_put(t)); // unbounded => must succeed + endfunction + +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_tlm_ifs.svh b/test_regress/t/t_uvm/tlm1/uvm_tlm_ifs.svh new file mode 100644 index 0000000000..64c65b5f1c --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_tlm_ifs.svh @@ -0,0 +1,231 @@ +// +//----------------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2014-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//----------------------------------------------------------------------------- + +`define UVM_TASK_ERROR "UVM TLM interface task not implemented" +`define UVM_FUNCTION_ERROR "UVM TLM interface function not implemented" + +//----------------------------------------------------------------------------- +// +// CLASS -- NODOCS -- uvm_tlm_if_base #(T1,T2) +// +// This class declares all of the methods of the UVM TLM API. +// +// Various subsets of these methods are combined to form primitive TLM +// interfaces, which are then paired in various ways to form more abstract +// "combination" UVM TLM interfaces. Components that require a particular interface +// use ports to convey that requirement. Components that provide a particular +// interface use exports to convey its availability. +// +// Communication between components is established by connecting ports to +// compatible exports, much like connecting module signal-level output ports to +// compatible input ports. The difference is that UVM ports and exports bind +// interfaces (groups of methods), not signals and wires. The methods of the +// interfaces so bound pass data as whole transactions (e.g. objects). +// The set of primitive and combination UVM TLM interfaces afford many choices for +// designing components that communicate at the transaction level. +// +//----------------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.2.4.1 +virtual class uvm_tlm_if_base #(type T1=int, type T2=int); + + // Group -- NODOCS -- Blocking put + + // Task -- NODOCS -- put + // + // Sends a user-defined transaction of type T. + // + // Components implementing the put method will block the calling thread if + // it cannot immediately accept delivery of the transaction. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.1 + virtual task put( input T1 t ); + uvm_report_error("put", `UVM_TASK_ERROR, UVM_NONE); + endtask + + // Group -- NODOCS -- Blocking get + + // Task -- NODOCS -- get + // + // Provides a new transaction of type T. + // + // The calling thread is blocked if the requested transaction cannot be + // provided immediately. The new transaction is returned in the provided + // output argument. + // + // The implementation of get must regard the transaction as consumed. + // Subsequent calls to get must return a different transaction instance. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.2 + virtual task get( output T2 t ); + uvm_report_error("get", `UVM_TASK_ERROR, UVM_NONE); + endtask + + + // Group -- NODOCS -- Blocking peek + + // Task -- NODOCS -- peek + // + // Obtain a new transaction without consuming it. + // + // If a transaction is available, then it is written to the provided output + // argument. If a transaction is not available, then the calling thread is + // blocked until one is available. + // + // The returned transaction is not consumed. A subsequent peek or get will + // return the same transaction. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.3 + virtual task peek( output T2 t ); + uvm_report_error("peek", `UVM_TASK_ERROR, UVM_NONE); + endtask + + + // Group -- NODOCS -- Non-blocking put + + // Function -- NODOCS -- try_put + // + // Sends a transaction of type T, if possible. + // + // If the component is ready to accept the transaction argument, then it does + // so and returns 1, otherwise it returns 0. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.4 + virtual function bit try_put( input T1 t ); + uvm_report_error("try_put", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Function -- NODOCS -- can_put + // + // Returns 1 if the component is ready to accept the transaction; 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.5 + virtual function bit can_put(); + uvm_report_error("can_put", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Group -- NODOCS -- Non-blocking get + + // Function -- NODOCS -- try_get + // + // Provides a new transaction of type T. + // + // If a transaction is immediately available, then it is written to the output + // argument and 1 is returned. Otherwise, the output argument is not modified + // and 0 is returned. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.6 + virtual function bit try_get( output T2 t ); + uvm_report_error("try_get", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Function -- NODOCS -- can_get + // + // Returns 1 if a new transaction can be provided immediately upon request, + // 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.7 + virtual function bit can_get(); + uvm_report_error("can_get", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Group -- NODOCS -- Non-blocking peek + + // Function -- NODOCS -- try_peek + // + // Provides a new transaction without consuming it. + // + // If available, a transaction is written to the output argument and 1 is + // returned. A subsequent peek or get will return the same transaction. If a + // transaction is not available, then the argument is unmodified and 0 is + // returned. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.8 + virtual function bit try_peek( output T2 t ); + uvm_report_error("try_peek", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Function -- NODOCS -- can_peek + // + // Returns 1 if a new transaction is available; 0 otherwise. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.9 + virtual function bit can_peek(); + uvm_report_error("can_ppeek", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Group -- NODOCS -- Blocking transport + + // Task -- NODOCS -- transport + // + // Executes the given request and returns the response in the given output + // argument. The calling thread may block until the operation is complete. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.10 + virtual task transport( input T1 req , output T2 rsp ); + uvm_report_error("transport", `UVM_TASK_ERROR, UVM_NONE); + endtask + + + // Group -- NODOCS -- Non-blocking transport + + // Task -- NODOCS -- nb_transport + // + // Executes the given request and returns the response in the given output + // argument. Completion of this operation must occur without blocking. + // + // If for any reason the operation could not be executed immediately, then + // a 0 must be returned; otherwise 1. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.11 + virtual function bit nb_transport(input T1 req, output T2 rsp); + uvm_report_error("nb_transport", `UVM_FUNCTION_ERROR, UVM_NONE); + return 0; + endfunction + + + // Group -- NODOCS -- Analysis + + // Function -- NODOCS -- write + // + // Broadcasts a user-defined transaction of type T to any number of listeners. + // The operation must complete without blocking. + + // @uvm-ieee 1800.2-2017 auto 12.2.4.2.12 + virtual function void write( input T1 t ); + uvm_report_error("write", `UVM_FUNCTION_ERROR, UVM_NONE); + endfunction + +endclass diff --git a/test_regress/t/t_uvm/tlm1/uvm_tlm_imps.svh b/test_regress/t/t_uvm/tlm1/uvm_tlm_imps.svh new file mode 100644 index 0000000000..ee938df300 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_tlm_imps.svh @@ -0,0 +1,229 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2018 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_TLM_IMPS_SVH +`define UVM_TLM_IMPS_SVH + +// +// These IMP macros define implementations of the uvm_*_port, uvm_*_export, +// and uvm_*_imp ports. +// + + +//--------------------------------------------------------------- +// Macros for implementations of UVM ports and exports + +/* +`define UVM_BLOCKING_PUT_IMP(imp, TYPE, arg) \ + task put (TYPE arg); \ + if (m_imp_list.size()) == 0) begin \ + uvm_report_error("Port Not Bound","Blocking put to unbound port will wait forever.", UVM_NONE); + @imp; + end + if (bcast_mode) begin \ + if (m_imp_list.size()) > 1) \ + fork + begin + foreach (m_imp_list[index]) \ + fork \ + automatic int i = index; \ + begin m_imp_list[i].put(arg); end \ + join_none \ + wait fork; \ + end \ + join \ + else \ + m_imp_list[0].put(arg); \ + end \ + else \ + if (imp != null) \ + imp.put(arg); \ + endtask \ + +`define UVM_NONBLOCKING_PUT_IMP(imp, TYPE, arg) \ + function bit try_put(input TYPE arg); \ + if (bcast_mode) begin \ + if (!can_put()) \ + return 0; \ + foreach (m_imp_list[index]) \ + void'(m_imp_list[index].try_put(arg)); \ + return 1; \ + end \ + if (imp != null) \ + return imp.try_put(arg)); \ + return 0; \ + endfunction \ + \ + function bit can_put(); \ + if (bcast_mode) begin \ + if (m_imp_list.size()) begin \ + foreach (m_imp_list[index]) begin \ + if (!m_imp_list[index].can_put() \ + return 0; \ + end \ + return 1; \ + end \ + return 0; \ + end \ + if (imp != null) \ + return imp.can_put(); \ + return 0; \ + endfunction + +*/ + +//----------------------------------------------------------------------- +// UVM TLM imp implementations + +`define UVM_BLOCKING_PUT_IMP(imp, TYPE, arg) \ + task put (TYPE arg); \ + imp.put(arg); \ + endtask + +`define UVM_NONBLOCKING_PUT_IMP(imp, TYPE, arg) \ + function bit try_put (TYPE arg); \ + return imp.try_put(arg); \ + endfunction \ + function bit can_put(); \ + return imp.can_put(); \ + endfunction + +`define UVM_BLOCKING_GET_IMP(imp, TYPE, arg) \ + task get (output TYPE arg); \ + imp.get(arg); \ + endtask + +`define UVM_NONBLOCKING_GET_IMP(imp, TYPE, arg) \ + function bit try_get (output TYPE arg); \ + return imp.try_get(arg); \ + endfunction \ + function bit can_get(); \ + return imp.can_get(); \ + endfunction + +`define UVM_BLOCKING_PEEK_IMP(imp, TYPE, arg) \ + task peek (output TYPE arg); \ + imp.peek(arg); \ + endtask + +`define UVM_NONBLOCKING_PEEK_IMP(imp, TYPE, arg) \ + function bit try_peek (output TYPE arg); \ + return imp.try_peek(arg); \ + endfunction \ + function bit can_peek(); \ + return imp.can_peek(); \ + endfunction + +`define UVM_BLOCKING_TRANSPORT_IMP(imp, REQ, RSP, req_arg, rsp_arg) \ + task transport (REQ req_arg, output RSP rsp_arg); \ + imp.transport(req_arg, rsp_arg); \ + endtask + +`define UVM_NONBLOCKING_TRANSPORT_IMP(imp, REQ, RSP, req_arg, rsp_arg) \ + function bit nb_transport (REQ req_arg, output RSP rsp_arg); \ + return imp.nb_transport(req_arg, rsp_arg); \ + endfunction + +`define UVM_PUT_IMP(imp, TYPE, arg) \ + `UVM_BLOCKING_PUT_IMP(imp, TYPE, arg) \ + `UVM_NONBLOCKING_PUT_IMP(imp, TYPE, arg) + +`define UVM_GET_IMP(imp, TYPE, arg) \ + `UVM_BLOCKING_GET_IMP(imp, TYPE, arg) \ + `UVM_NONBLOCKING_GET_IMP(imp, TYPE, arg) + +`define UVM_PEEK_IMP(imp, TYPE, arg) \ + `UVM_BLOCKING_PEEK_IMP(imp, TYPE, arg) \ + `UVM_NONBLOCKING_PEEK_IMP(imp, TYPE, arg) + +`define UVM_BLOCKING_GET_PEEK_IMP(imp, TYPE, arg) \ + `UVM_BLOCKING_GET_IMP(imp, TYPE, arg) \ + `UVM_BLOCKING_PEEK_IMP(imp, TYPE, arg) + +`define UVM_NONBLOCKING_GET_PEEK_IMP(imp, TYPE, arg) \ + `UVM_NONBLOCKING_GET_IMP(imp, TYPE, arg) \ + `UVM_NONBLOCKING_PEEK_IMP(imp, TYPE, arg) + +`define UVM_GET_PEEK_IMP(imp, TYPE, arg) \ + `UVM_BLOCKING_GET_PEEK_IMP(imp, TYPE, arg) \ + `UVM_NONBLOCKING_GET_PEEK_IMP(imp, TYPE, arg) + +`define UVM_TRANSPORT_IMP(imp, REQ, RSP, req_arg, rsp_arg) \ + `UVM_BLOCKING_TRANSPORT_IMP(imp, REQ, RSP, req_arg, rsp_arg) \ + `UVM_NONBLOCKING_TRANSPORT_IMP(imp, REQ, RSP, req_arg, rsp_arg) + + + +`define UVM_TLM_GET_TYPE_NAME(NAME) \ + virtual function string get_type_name(); \ + return NAME; \ + endfunction + +`define UVM_PORT_COMMON(MASK,TYPE_NAME) \ + function new (string name, uvm_component parent, \ + int min_size=1, int max_size=1); \ + super.new (name, parent, UVM_PORT, min_size, max_size); \ + m_if_mask = MASK; \ + endfunction \ + `UVM_TLM_GET_TYPE_NAME(TYPE_NAME) + +`define UVM_SEQ_PORT(MASK,TYPE_NAME) \ + function new (string name, uvm_component parent, \ + int min_size=0, int max_size=1); \ + super.new (name, parent, UVM_PORT, min_size, max_size); \ + m_if_mask = MASK; \ + endfunction \ + `UVM_TLM_GET_TYPE_NAME(TYPE_NAME) + +`define UVM_EXPORT_COMMON(MASK,TYPE_NAME) \ + function new (string name, uvm_component parent, \ + int min_size=1, int max_size=1); \ + super.new (name, parent, UVM_EXPORT, min_size, max_size); \ + m_if_mask = MASK; \ + endfunction \ + `UVM_TLM_GET_TYPE_NAME(TYPE_NAME) + +`define UVM_IMP_COMMON(MASK,TYPE_NAME,IMP) \ + local IMP m_imp; \ + function new (string name, IMP imp); \ + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); \ + m_imp = imp; \ + m_if_mask = MASK; \ + endfunction \ + `UVM_TLM_GET_TYPE_NAME(TYPE_NAME) + +`define UVM_MS_IMP_COMMON(MASK,TYPE_NAME) \ + local this_req_type m_req_imp; \ + local this_rsp_type m_rsp_imp; \ + function new (string name, this_imp_type imp, \ + this_req_type req_imp = null, this_rsp_type rsp_imp = null); \ + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); \ + if(req_imp==null) $cast(req_imp, imp); \ + if(rsp_imp==null) $cast(rsp_imp, imp); \ + m_req_imp = req_imp; \ + m_rsp_imp = rsp_imp; \ + m_if_mask = MASK; \ + endfunction \ + `UVM_TLM_GET_TYPE_NAME(TYPE_NAME) + +`endif diff --git a/test_regress/t/t_uvm/tlm1/uvm_tlm_req_rsp.svh b/test_regress/t/t_uvm/tlm1/uvm_tlm_req_rsp.svh new file mode 100644 index 0000000000..02ec54aa07 --- /dev/null +++ b/test_regress/t/t_uvm/tlm1/uvm_tlm_req_rsp.svh @@ -0,0 +1,342 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//---------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +// Title -- NODOCS -- UVM TLM Channel Classes +//------------------------------------------------------------------------------ +// This section defines built-in UVM TLM channel classes. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_tlm_req_rsp_channel #(REQ,RSP) +// +// The uvm_tlm_req_rsp_channel contains a request FIFO of type ~REQ~ and a response +// FIFO of type ~RSP~. These FIFOs can be of any size. This channel is +// particularly useful for dealing with pipelined protocols where the request +// and response are not tightly coupled. +// +// Type parameters: +// +// REQ - Type of the request transactions conveyed by this channel. +// RSP - Type of the response transactions conveyed by this channel. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 12.2.9.1.1 +class uvm_tlm_req_rsp_channel #(type REQ=int, type RSP=REQ) extends uvm_component; + + typedef uvm_tlm_req_rsp_channel #(REQ, RSP) this_type; + + `uvm_component_param_utils(uvm_tlm_req_rsp_channel#(REQ,RSP)) + `uvm_type_name_decl("uvm_tlm_req_rsp_channel #(REQ,RSP)") + + // Port -- NODOCS -- put_request_export + // + // The put_export provides both the blocking and non-blocking put interface + // methods to the request FIFO: + // + //| task put (input T t); + //| function bit can_put (); + //| function bit try_put (input T t); + // + // Any put port variant can connect and send transactions to the request FIFO + // via this export, provided the transaction types match. + + uvm_put_export #(REQ) put_request_export; + + + // Port -- NODOCS -- get_peek_response_export + // + // The get_peek_response_export provides all the blocking and non-blocking get + // and peek interface methods to the response FIFO: + // + //| task get (output T t); + //| function bit can_get (); + //| function bit try_get (output T t); + //| task peek (output T t); + //| function bit can_peek (); + //| function bit try_peek (output T t); + // + // Any get or peek port variant can connect to and retrieve transactions from + // the response FIFO via this export, provided the transaction types match. + + uvm_get_peek_export #(RSP) get_peek_response_export; + + + // Port -- NODOCS -- get_peek_request_export + // + // The get_peek_export provides all the blocking and non-blocking get and peek + // interface methods to the response FIFO: + // + //| task get (output T t); + //| function bit can_get (); + //| function bit try_get (output T t); + //| task peek (output T t); + //| function bit can_peek (); + //| function bit try_peek (output T t); + // + // Any get or peek port variant can connect to and retrieve transactions from + // the response FIFO via this export, provided the transaction types match. + + + uvm_get_peek_export #(REQ) get_peek_request_export; + + + // Port -- NODOCS -- put_response_export + // + // The put_export provides both the blocking and non-blocking put interface + // methods to the response FIFO: + // + //| task put (input T t); + //| function bit can_put (); + //| function bit try_put (input T t); + // + // Any put port variant can connect and send transactions to the response FIFO + // via this export, provided the transaction types match. + + uvm_put_export #(RSP) put_response_export; + + + // Port -- NODOCS -- request_ap + // + // Transactions passed via ~put~ or ~try_put~ (via any port connected to the + // put_request_export) are sent out this port via its write method. + // + //| function void write (T t); + // + // All connected analysis exports and imps will receive these transactions. + + uvm_analysis_port #(REQ) request_ap; + + + // Port -- NODOCS -- response_ap + // + // Transactions passed via ~put~ or ~try_put~ (via any port connected to the + // put_response_export) are sent out this port via its write method. + // + //| function void write (T t); + // + // All connected analysis exports and imps will receive these transactions. + + uvm_analysis_port #(RSP) response_ap; + + + // Port -- NODOCS -- master_export + // + // Exports a single interface that allows a master to put requests and get or + // peek responses. It is a combination of the put_request_export and + // get_peek_response_export. + + uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) master_export; + + + // Port -- NODOCS -- slave_export + // + // Exports a single interface that allows a slave to get or peek requests and + // to put responses. It is a combination of the get_peek_request_export + // and put_response_export. + + uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) slave_export; + + // port aliases for backward compatibility + uvm_put_export #(REQ) blocking_put_request_export, + nonblocking_put_request_export; + uvm_get_peek_export #(REQ) get_request_export, + blocking_get_request_export, + nonblocking_get_request_export, + peek_request_export, + blocking_peek_request_export, + nonblocking_peek_request_export, + blocking_get_peek_request_export, + nonblocking_get_peek_request_export; + + uvm_put_export #(RSP) blocking_put_response_export, + nonblocking_put_response_export; + uvm_get_peek_export #(RSP) get_response_export, + blocking_get_response_export, + nonblocking_get_response_export, + peek_response_export, + blocking_peek_response_export, + nonblocking_peek_response_export, + blocking_get_peek_response_export, + nonblocking_get_peek_response_export; + + uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) + blocking_master_export, + nonblocking_master_export; + + uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) + blocking_slave_export, + nonblocking_slave_export; + // internal fifos + protected uvm_tlm_fifo #(REQ) m_request_fifo; + protected uvm_tlm_fifo #(RSP) m_response_fifo; + + + // Function -- NODOCS -- new + // + // The ~name~ and ~parent~ are the standard constructor arguments. + // The ~parent~ must be ~null~ if this component is defined within a static + // component such as a module, program block, or interface. The last two + // arguments specify the request and response FIFO sizes, which have default + // values of 1. + + // @uvm-ieee 1800.2-2017 auto 12.2.9.1.11 + function new (string name, uvm_component parent=null, + int request_fifo_size=1, + int response_fifo_size=1); + + super.new (name, parent); + + m_request_fifo = new ("request_fifo", this, request_fifo_size); + m_response_fifo = new ("response_fifo", this, response_fifo_size); + + request_ap = new ("request_ap", this); + response_ap = new ("response_ap", this); + + put_request_export = new ("put_request_export", this); + get_peek_request_export = new ("get_peek_request_export", this); + + put_response_export = new ("put_response_export", this); + get_peek_response_export = new ("get_peek_response_export", this); + + master_export = new ("master_export", this, m_request_fifo, m_response_fifo); + slave_export = new ("slave_export", this, m_request_fifo, m_response_fifo); + + create_aliased_exports(); + + set_report_id_action_hier(s_connection_error_id, UVM_NO_ACTION); + + endfunction + + virtual function void connect_phase(uvm_phase phase); + put_request_export.connect (m_request_fifo.put_export); + get_peek_request_export.connect (m_request_fifo.get_peek_export); + m_request_fifo.put_ap.connect (request_ap); + put_response_export.connect (m_response_fifo.put_export); + get_peek_response_export.connect (m_response_fifo.get_peek_export); + m_response_fifo.put_ap.connect (response_ap); + endfunction + + function void create_aliased_exports(); + // request + blocking_put_request_export = put_request_export; + nonblocking_put_request_export = put_request_export; + get_request_export = get_peek_request_export; + blocking_get_request_export = get_peek_request_export; + nonblocking_get_request_export = get_peek_request_export; + peek_request_export = get_peek_request_export; + blocking_peek_request_export = get_peek_request_export; + nonblocking_peek_request_export = get_peek_request_export; + blocking_get_peek_request_export = get_peek_request_export; + nonblocking_get_peek_request_export = get_peek_request_export; + + // response + blocking_put_response_export = put_response_export; + nonblocking_put_response_export = put_response_export; + get_response_export = get_peek_response_export; + blocking_get_response_export = get_peek_response_export; + nonblocking_get_response_export = get_peek_response_export; + peek_response_export = get_peek_response_export; + blocking_peek_response_export = get_peek_response_export; + nonblocking_peek_response_export = get_peek_response_export; + blocking_get_peek_response_export = get_peek_response_export; + nonblocking_get_peek_response_export = get_peek_response_export; + + // master/slave + blocking_master_export = master_export; + nonblocking_master_export = master_export; + blocking_slave_export = slave_export; + nonblocking_slave_export = slave_export; + endfunction + +endclass + + +//------------------------------------------------------------------------------ +// +// CLASS -- NODOCS -- uvm_tlm_transport_channel #(REQ,RSP) +// +// A uvm_tlm_transport_channel is a that implements +// the transport interface. It is useful when modeling a non-pipelined bus at +// the transaction level. Because the requests and responses have a tightly +// coupled one-to-one relationship, the request and response FIFO sizes are both +// set to one. +// +//------------------------------------------------------------------------------ + +// @uvm-ieee 1800.2-2017 auto 12.2.9.2.1 +class uvm_tlm_transport_channel #(type REQ=int, type RSP=REQ) + extends uvm_tlm_req_rsp_channel #(REQ, RSP); + + `uvm_component_param_utils(uvm_tlm_transport_channel#(REQ,RSP)) + `uvm_type_name_decl("uvm_tlm_transport_channel #(REQ,RSP)") + + typedef uvm_tlm_transport_channel #(REQ, RSP) this_type; + + // Port -- NODOCS -- transport_export + // + // The put_export provides both the blocking and non-blocking transport + // interface methods to the response FIFO: + // + //| task transport(REQ request, output RSP response); + //| function bit nb_transport(REQ request, output RSP response); + // + // Any transport port variant can connect to and send requests and retrieve + // responses via this export, provided the transaction types match. Upon + // return, the response argument carries the response to the request. + + uvm_transport_imp #(REQ, RSP, this_type) transport_export; + + + // Function -- NODOCS -- new + // + // The ~name~ and ~parent~ are the standard constructor + // arguments. The ~parent~ must be ~null~ if this component is defined within a + // statically elaborated construct such as a module, program block, or + // interface. + + // @uvm-ieee 1800.2-2017 auto 12.2.9.2.3 + function new (string name, uvm_component parent=null); + super.new(name, parent, 1, 1); + transport_export = new("transport_export", this); + endfunction + + // @uvm-ieee 1800.2-2017 auto 12.2.9.2.2 + task transport (REQ request, output RSP response ); + this.m_request_fifo.put( request ); + this.m_response_fifo.get( response ); + endtask + + // @uvm-ieee 1800.2-2017 auto 12.2.9.2.2 + function bit nb_transport (REQ req, output RSP rsp ); + if(this.m_request_fifo.try_put(req)) + return this.m_response_fifo.try_get(rsp); + else + return 0; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2.svh new file mode 100644 index 0000000000..bb710577fa --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2.svh @@ -0,0 +1,30 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2017 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, 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. +//---------------------------------------------------------------------- + + `include "tlm2/uvm_tlm2_defines.svh" + `include "tlm2/uvm_tlm_time.svh" + `include "tlm2/uvm_tlm2_generic_payload.svh" + `include "tlm2/uvm_tlm2_ifs.svh" + `include "tlm2/uvm_tlm2_imps.svh" + `include "tlm2/uvm_tlm2_ports.svh" + `include "tlm2/uvm_tlm2_exports.svh" + `include "tlm2/uvm_tlm2_sockets_base.svh" + `include "tlm2/uvm_tlm2_sockets.svh" diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_defines.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_defines.svh new file mode 100644 index 0000000000..cda8130069 --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_defines.svh @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2014-2015 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- Interface Masks +// +// Each of the following macros is a mask that identifies which +// interfaces a particular port requires or export provides. The +// interfaces are identified by bit position and can be OR'ed together +// for combination ports/exports. The mask is used to do run-time +// interface type checking of port/export connections. +//---------------------------------------------------------------------- + +// MACRO -- NODOCS -- `UVM_TLM_NB_FW_MASK +// +// Define Non blocking Forward mask onehot assignment = 'b001 +`define UVM_TLM_NB_FW_MASK (1<<0) + +// MACRO -- NODOCS -- `UVM_TLM_NB_BW_MASK +// +// Define Non blocking backward mask onehot assignment = 'b010 +`define UVM_TLM_NB_BW_MASK (1<<1) + +// MACRO -- NODOCS -- `UVM_TLM_B_MASK +// +// Define blocking mask onehot assignment = 'b100 +`define UVM_TLM_B_MASK (1<<2) diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_exports.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_exports.svh new file mode 100644 index 0000000000..78878428a1 --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_exports.svh @@ -0,0 +1,69 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM TLM 2 Export Classes +// +// This section defines the export classes for connecting TLM2 +// interfaces. +//---------------------------------------------------------------------- + + +// Class -- NODOCS -- uvm_tlm_b_transport_export +// +// Blocking transport export class. + +// @uvm-ieee 1800.2-2017 auto 12.3.7.1 +class uvm_tlm_b_transport_export #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + `UVM_EXPORT_COMMON(`UVM_TLM_B_MASK, "uvm_tlm_b_transport_export") + `UVM_TLM_B_TRANSPORT_IMP(this.m_if, T, t, delay) +endclass + + + +// Class -- NODOCS -- uvm_tlm_nb_transport_fw_export +// +// Non-blocking forward transport export class + +// @uvm-ieee 1800.2-2017 auto 12.3.7.2 +class uvm_tlm_nb_transport_fw_export #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + `UVM_EXPORT_COMMON(`UVM_TLM_NB_FW_MASK, "uvm_tlm_nb_transport_fw_export") + `UVM_TLM_NB_TRANSPORT_FW_IMP(this.m_if, T, P, t, p, delay) +endclass + + + +// Class -- NODOCS -- uvm_tlm_nb_transport_bw_export +// +// Non-blocking backward transport export class + +// @uvm-ieee 1800.2-2017 auto 12.3.7.3 +class uvm_tlm_nb_transport_bw_export #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + // Function -- NODOCS -- new + `UVM_EXPORT_COMMON(`UVM_TLM_NB_BW_MASK, "uvm_tlm_nb_transport_bw_export") + `UVM_TLM_NB_TRANSPORT_BW_IMP(this.m_if, T, P, t, p, delay) +endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_generic_payload.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_generic_payload.svh new file mode 100644 index 0000000000..9a24ba42af --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_generic_payload.svh @@ -0,0 +1,1119 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2012 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2013-2018 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM TLM Generic Payload & Extensions +//---------------------------------------------------------------------- +// The Generic Payload transaction represents a generic +// bus read/write access. It is used as the default transaction in +// TLM2 blocking and nonblocking transport interfaces. +//---------------------------------------------------------------------- + + +//--------------- +// Group -- NODOCS -- Globals +//--------------- +// +// Defines, Constants, enums. + + +// Enum -- NODOCS -- uvm_tlm_command_e +// +// Command attribute type definition +// +// UVM_TLM_READ_COMMAND - Bus read operation +// +// UVM_TLM_WRITE_COMMAND - Bus write operation +// +// UVM_TLM_IGNORE_COMMAND - No bus operation. + +typedef enum +{ + UVM_TLM_READ_COMMAND, + UVM_TLM_WRITE_COMMAND, + UVM_TLM_IGNORE_COMMAND +} uvm_tlm_command_e; + + +// Enum -- NODOCS -- uvm_tlm_response_status_e +// +// Response status attribute type definition +// +// UVM_TLM_OK_RESPONSE - Bus operation completed successfully +// +// UVM_TLM_INCOMPLETE_RESPONSE - Transaction was not delivered to target +// +// UVM_TLM_GENERIC_ERROR_RESPONSE - Bus operation had an error +// +// UVM_TLM_ADDRESS_ERROR_RESPONSE - Invalid address specified +// +// UVM_TLM_COMMAND_ERROR_RESPONSE - Invalid command specified +// +// UVM_TLM_BURST_ERROR_RESPONSE - Invalid burst specified +// +// UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE - Invalid byte enabling specified +// + +typedef enum +{ + UVM_TLM_OK_RESPONSE = 1, + UVM_TLM_INCOMPLETE_RESPONSE = 0, + UVM_TLM_GENERIC_ERROR_RESPONSE = -1, + UVM_TLM_ADDRESS_ERROR_RESPONSE = -2, + UVM_TLM_COMMAND_ERROR_RESPONSE = -3, + UVM_TLM_BURST_ERROR_RESPONSE = -4, + UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE = -5 +} uvm_tlm_response_status_e; + + +typedef class uvm_tlm_extension_base; + + +//----------------------- +// Group -- NODOCS -- Generic Payload +//----------------------- + +//---------------------------------------------------------------------- +// Class: uvm_tlm_generic_payload +// +// Implementation of uvm_tlm_generic_payload, as described in +// section 12.3.4.2.1 of 1800.2-2017. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.4.2.1 +class uvm_tlm_generic_payload extends uvm_sequence_item; + + // Variable -- NODOCS -- m_address + // + // Address for the bus operation. + // Should be set or read using the and + // methods. The variable should be used only when constraining. + // + // For a read command or a write command, the target shall + // interpret the current value of the address attribute as the start + // address in the system memory map of the contiguous block of data + // being read or written. + // The address associated with any given byte in the data array is + // dependent upon the address attribute, the array index, the + // streaming width attribute, the endianness and the width of the physical bus. + // + // If the target is unable to execute the transaction with + // the given address attribute (because the address is out-of-range, + // for example) it shall generate a standard error response. The + // recommended response status is ~UVM_TLM_ADDRESS_ERROR_RESPONSE~. + // + rand bit [63:0] m_address; + + + // Variable -- NODOCS -- m_command + // + // Bus operation type. + // Should be set using the , or methods + // and read using the , or methods. + // The variable should be used only when constraining. + // + // If the target is unable to execute a read or write command, it + // shall generate a standard error response. The + // recommended response status is UVM_TLM_COMMAND_ERROR_RESPONSE. + // + // On receipt of a generic payload transaction with the command + // attribute equal to UVM_TLM_IGNORE_COMMAND, the target shall not execute + // a write command or a read command not modify any data. + // The target may, however, use the value of any attribute in + // the generic payload, including any extensions. + // + // The command attribute shall be set by the initiator, and shall + // not be overwritten by any interconnect + // + rand uvm_tlm_command_e m_command; + + + // Variable -- NODOCS -- m_data + // + // Data read or to be written. + // Should be set and read using the or methods + // The variable should be used only when constraining. + // + // For a read command or a write command, the target shall copy data + // to or from the data array, respectively, honoring the semantics of + // the remaining attributes of the generic payload. + // + // For a write command or UVM_TLM_IGNORE_COMMAND, the contents of the + // data array shall be set by the initiator, and shall not be + // overwritten by any interconnect component or target. For a read + // command, the contents of the data array shall be overwritten by the + // target (honoring the semantics of the byte enable) but by no other + // component. + // + // Unlike the OSCI TLM-2.0 LRM, there is no requirement on the endiannes + // of multi-byte data in the generic payload to match the host endianness. + // Unlike C++, it is not possible in SystemVerilog to cast an arbitrary + // data type as an array of bytes. Therefore, matching the host + // endianness is not necessary. In contrast, arbitrary data types may be + // converted to and from a byte array using the streaming operator and + // objects may be further converted using the + // and methods. + // All that is required is that a consistent mechanism is used to + // fill the payload data array and later extract data from it. + // + // Should a generic payload be transferred to/from a SystemC model, + // it will be necessary for any multi-byte data in that generic payload + // to use/be interpreted using the host endianness. + // However, this process is currently outside the scope of this standard. + // + byte unsigned m_data[]; + + + // Variable -- NODOCS -- m_length + // + // The number of bytes to be copied to or from the array, + // inclusive of any bytes disabled by the attribute. + // + // The data length attribute shall be set by the initiator, + // and shall not be overwritten by any interconnect component or target. + // + // The data length attribute shall not be set to 0. + // In order to transfer zero bytes, the attribute + // should be set to . + // + rand int unsigned m_length; + + + // Variable -- NODOCS -- m_response_status + // + // Status of the bus operation. + // Should be set using the method + // and read using the , , + // or methods. + // The variable should be used only when constraining. + // + // The response status attribute shall be set to + // UVM_TLM_INCOMPLETE_RESPONSE by the initiator, and may + // be overwritten by the target. The response status attribute + // should not be overwritten by any interconnect + // component, because the default value UVM_TLM_INCOMPLETE_RESPONSE + // indicates that the transaction was not delivered to the target. + // + // The target may set the response status attribute to UVM_TLM_OK_RESPONSE + // to indicate that it was able to execute the command + // successfully, or to one of the five error responses + // to indicate an error. The target should choose the appropriate + // error response depending on the cause of the error. + // If a target detects an error but is unable to select a specific + // error response, it may set the response status to + // UVM_TLM_GENERIC_ERROR_RESPONSE. + // + // The target shall be responsible for setting the response status + // attribute at the appropriate point in the + // lifetime of the transaction. In the case of the blocking + // transport interface, this means before returning + // control from b_transport. In the case of the non-blocking + // transport interface and the base protocol, this + // means before sending the BEGIN_RESP phase or returning a value of UVM_TLM_COMPLETED. + // + // It is recommended that the initiator should always check the + // response status attribute on receiving a + // transition to the BEGIN_RESP phase or after the completion of + // the transaction. An initiator may choose + // to ignore the response status if it is known in advance that the + // value will be UVM_TLM_OK_RESPONSE, + // perhaps because it is known in advance that the initiator is + // only connected to targets that always return + // UVM_TLM_OK_RESPONSE, but in general this will not be the case. In + // other words, the initiator ignores the + // response status at its own risk. + // + rand uvm_tlm_response_status_e m_response_status; + + + // Variable -- NODOCS -- m_dmi + // + // DMI mode is not yet supported in the UVM TLM2 subset. + // This variable is provided for completeness and interoperability + // with SystemC. + // + bit m_dmi; + + + // Variable -- NODOCS -- m_byte_enable + // + // Indicates valid array elements. + // Should be set and read using the or methods + // The variable should be used only when constraining. + // + // The elements in the byte enable array shall be interpreted as + // follows. A value of 8'h00 shall indicate that that + // corresponding byte is disabled, and a value of 8'hFF shall + // indicate that the corresponding byte is enabled. + // + // Byte enables may be used to create burst transfers where the + // address increment between each beat is + // greater than the number of significant bytes transferred on each + // beat, or to place words in selected byte + // lanes of a bus. At a more abstract level, byte enables may be + // used to create "lacy bursts" where the data array of the generic + // payload has an arbitrary pattern of holes punched in it. + // + // The byte enable mask may be defined by a small pattern applied + // repeatedly or by a large pattern covering the whole data array. + // The byte enable array may be empty, in which case byte enables + // shall not be used for the current transaction. + // + // The byte enable array shall be set by the initiator and shall + // not be overwritten by any interconnect component or target. + // + // If the byte enable pointer is not empty, the target shall either + // implement the semantics of the byte enable as defined below or + // shall generate a standard error response. The recommended response + // status is UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE. + // + // In the case of a write command, any interconnect component or + // target should ignore the values of any disabled bytes in the + // array. In the case of a read command, any interconnect + // component or target should not modify the values of disabled + // bytes in the array. + // + byte unsigned m_byte_enable[]; + + + // Variable -- NODOCS -- m_byte_enable_length + // + // The number of elements in the array. + // + // It shall be set by the initiator, and shall not be overwritten + // by any interconnect component or target. + // + rand int unsigned m_byte_enable_length; + + + // Variable -- NODOCS -- m_streaming_width + // + // Number of bytes transferred on each beat. + // Should be set and read using the or + // methods + // The variable should be used only when constraining. + // + // Streaming affects the way a component should interpret the data + // array. A stream consists of a sequence of data transfers occurring + // on successive notional beats, each beat having the same start + // address as given by the generic payload address attribute. The + // streaming width attribute shall determine the width of the stream, + // that is, the number of bytes transferred on each beat. In other + // words, streaming affects the local address associated with each + // byte in the data array. In all other respects, the organization of + // the data array is unaffected by streaming. + // + // The bytes within the data array have a corresponding sequence of + // local addresses within the component accessing the generic payload + // transaction. The lowest address is given by the value of the + // address attribute. The highest address is given by the formula + // address_attribute + streaming_width - 1. The address to or from + // which each byte is being copied in the target shall be set to the + // value of the address attribute at the start of each beat. + // + // With respect to the interpretation of the data array, a single + // transaction with a streaming width shall be functionally equivalent + // to a sequence of transactions each having the same address as the + // original transaction, each having a data length attribute equal to + // the streaming width of the original, and each with a data array + // that is a different subset of the original data array on each + // beat. This subset effectively steps down the original data array + // maintaining the sequence of bytes. + // + // A streaming width of 0 indicates that a streaming transfer + // is not required. it is equivalent to a streaming width + // value greater than or equal to the size of the array. + // + // Streaming may be used in conjunction with byte enables, in which + // case the streaming width would typically be equal to the byte + // enable length. It would also make sense to have the streaming width + // a multiple of the byte enable length. Having the byte enable length + // a multiple of the streaming width would imply that different bytes + // were enabled on each beat. + // + // If the target is unable to execute the transaction with the + // given streaming width, it shall generate a standard error + // response. The recommended response status is + // TLM_BURST_ERROR_RESPONSE. + // + rand int unsigned m_streaming_width; + + protected uvm_tlm_extension_base m_extensions [uvm_tlm_extension_base]; + local uvm_tlm_extension_base m_rand_exts[]; + + + `uvm_object_utils(uvm_tlm_generic_payload) + + + // Function -- NODOCS -- new + // + // Create a new instance of the generic payload. Initialize all the + // members to their default values. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.3 + function new(string name=""); + super.new(name); + m_address = 0; + m_command = UVM_TLM_IGNORE_COMMAND; + m_length = 0; + m_response_status = UVM_TLM_INCOMPLETE_RESPONSE; + m_dmi = 0; + m_byte_enable_length = 0; + m_streaming_width = 0; + endfunction + + + // Function- do_print + // + function void do_print(uvm_printer printer); + byte unsigned be; + super.do_print(printer); + printer.print_field_int ("address", m_address, 64, UVM_HEX); + printer.print_generic ("command", "uvm_tlm_command_e", 32, m_command.name()); + printer.print_generic ("response_status", "uvm_tlm_response_status_e", + 32, m_response_status.name()); + printer.print_field_int ("streaming_width", m_streaming_width, 32, UVM_HEX); + + printer.print_array_header("data", m_length, "darray(byte)"); + for (int i=0; i < m_length && i < m_data.size(); i++) begin + if (m_byte_enable_length) begin + be = m_byte_enable[i % m_byte_enable_length]; + printer.print_generic ($sformatf("[%0d]",i), "byte", 8, + $sformatf("'h%h%s",m_data[i],((be=='hFF) ? "" : " x"))); + end + else + printer.print_generic ($sformatf("[%0d]",i), "byte", 8, + $sformatf("'h%h",m_data[i])); + end + printer.print_array_footer(); + + begin + string name; + printer.print_array_header("extensions", m_extensions.num(), "aa(obj,obj)"); + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = m_extensions[ext_]; + name = {"[",ext.get_name(),"]"}; + printer.print_object(name, ext, "["); + end + printer.print_array_footer(); + end + endfunction + + + // Function- do_copy + // + function void do_copy(uvm_object rhs); + uvm_tlm_generic_payload gp; + super.do_copy(rhs); + $cast(gp, rhs); + m_address = gp.m_address; + m_command = gp.m_command; + m_data = gp.m_data; + m_dmi = gp.m_dmi; + m_length = gp.m_length; + m_response_status = gp.m_response_status; + m_byte_enable = gp.m_byte_enable; + m_streaming_width = gp.m_streaming_width; + m_byte_enable_length = gp.m_byte_enable_length; + + m_extensions.delete(); + foreach (gp.m_extensions[ext]) + $cast(m_extensions[ext], gp.m_extensions[ext].clone()); + + endfunction + +`define m_uvm_tlm_fast_compare_int(VALUE,RADIX,NAME="") \ + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && \ + ((VALUE) != (gp.VALUE)) ) begin \ + string name = (NAME == "") ? `"VALUE`" : NAME; \ + void'(comparer.compare_field_int(name , VALUE, gp.VALUE, $bits(VALUE), RADIX)); \ + end + +`define m_uvm_tlm_fast_compare_enum(VALUE,TYPE,NAME="") \ + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && \ + ((VALUE) != (gp.VALUE)) ) begin \ + string name = (NAME == "") ? `"VALUE`" : NAME; \ + void'( comparer.compare_string(name, \ + $sformatf("%s'(%s)", `"TYPE`", VALUE.name()), \ + $sformatf("%s'(%s)", `"TYPE`", gp.VALUE.name())) ); \ + end + + // Function: do_compare + // Compares this generic payload to ~rhs~. + // + // The method compares the fields of this instance to + // to those of ~rhs~. All fields are compared, however if byte + // enables are being used, then non-enabled bytes of data are + // skipped. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + function bit do_compare(uvm_object rhs, uvm_comparer comparer); + uvm_tlm_generic_payload gp; + do_compare = super.do_compare(rhs, comparer); + $cast(gp, rhs); + + `m_uvm_tlm_fast_compare_int(m_address, UVM_HEX) + `m_uvm_tlm_fast_compare_enum(m_command, uvm_tlm_command_e) + `m_uvm_tlm_fast_compare_int(m_length, UVM_UNSIGNED) + `m_uvm_tlm_fast_compare_int(m_dmi, UVM_BIN) + `m_uvm_tlm_fast_compare_int(m_byte_enable_length, UVM_UNSIGNED) + `m_uvm_tlm_fast_compare_enum(m_response_status, uvm_tlm_response_status_e) + `m_uvm_tlm_fast_compare_int(m_streaming_width, UVM_UNSIGNED) + + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + m_byte_enable_length == gp.m_byte_enable_length ) begin + + for (int i=0; i < m_byte_enable_length && i < m_byte_enable.size(); i++) begin + `m_uvm_tlm_fast_compare_int(m_byte_enable[i], UVM_HEX, $sformatf("m_byte_enable[%0d]", i)) + end + end + + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + m_length == gp.m_length ) begin + + byte unsigned be; + for (int i=0; i < m_length && i < m_data.size(); i++) begin + if (m_byte_enable_length) begin + be = m_byte_enable[i % m_byte_enable_length]; + end + else begin + be = 8'hFF; + end + `m_uvm_tlm_fast_compare_int(m_data[i] & be, UVM_HEX, $sformatf("m_data[%0d] & %0x", i, be)) + end + end + + if ( !comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold()) ) + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = ext_; + uvm_tlm_extension_base rhs_ext = gp.m_extensions.exists(ext) ? + gp.m_extensions[ext] : null; + + void'(comparer.compare_object(ext.get_name(), + m_extensions[ext], rhs_ext)); + + if ( !comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold()) ) + break; + + end + + if (comparer.get_result()) begin + string msg = $sformatf("GP miscompare between '%s' and '%s':\nlhs = %s\nrhs = %s", + get_full_name(), gp.get_full_name(), + this.convert2string(), gp.convert2string()); + comparer.print_msg(msg); + end + + return (comparer.get_result() == 0); + endfunction + +`undef m_uvm_tlm_fast_compare_int +`undef m_uvm_tlm_fast_compare_enum + + // Function: do_pack + // Packs the fields of the payload in ~packer~. + // + // Fields are packed in the following order: + // - + // - + // - + // - + // - (if is greater than 0) + // - + // - + // - (if is greater than 0) + // - + // + // Only bytes of the array are packed, + // and a fatal message is generated if ~m_data.size()~ is less + // than . The same is true for + // and . + // + // Note: The extensions are not packed. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + + function void do_pack(uvm_packer packer); + super.do_pack(packer); + if (m_length > m_data.size()) + `uvm_fatal("PACK_DATA_ARR", + $sformatf("Data array m_length property (%0d) greater than m_data.size (%0d)", + m_length,m_data.size())) + if (m_byte_enable_length > m_byte_enable.size()) + `uvm_fatal("PACK_DATA_ARR", + $sformatf("Data array m_byte_enable_length property (%0d) greater than m_byte_enable.size (%0d)", + m_byte_enable_length,m_byte_enable.size())) + `uvm_pack_intN (m_address,64) + `uvm_pack_enumN (m_command,32) + `uvm_pack_intN (m_length,32) + `uvm_pack_intN (m_dmi,1) + for (int i=0; i/ arrays are reallocated if the + // new size is greater than their current size; otherwise the + // existing array allocations are kept. + // + // Note: The extensions are not unpacked. + // + // @uvm-contrib This API is being considered for potential contribution to 1800.2 + function void do_unpack(uvm_packer packer); + super.do_unpack(packer); + `uvm_unpack_intN (m_address,64) + `uvm_unpack_enumN (m_command, 32, uvm_tlm_command_e) + `uvm_unpack_intN (m_length,32) + `uvm_unpack_intN (m_dmi, 1) + if (m_data.size() < m_length) + m_data = new[m_length]; + foreach (m_data[i]) + `uvm_unpack_intN(m_data[i],8) + `uvm_unpack_enumN (m_response_status, 32, uvm_tlm_response_status_e) + `uvm_unpack_intN (m_byte_enable_length,32) + if (m_byte_enable.size() < m_byte_enable_length) + m_byte_enable = new[m_byte_enable_length]; + for (int i=0; i variable + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.13 + virtual function uvm_tlm_command_e get_command(); + return m_command; + endfunction + + // Function -- NODOCS -- set_command + // + // Set the value of the variable + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.14 + virtual function void set_command(uvm_tlm_command_e command); + m_command = command; + endfunction + + // Function -- NODOCS -- is_read + // + // Returns true if the current value of the variable + // is ~UVM_TLM_READ_COMMAND~. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.15 + virtual function bit is_read(); + return (m_command == UVM_TLM_READ_COMMAND); + endfunction + + // Function -- NODOCS -- set_read + // + // Set the current value of the variable + // to ~UVM_TLM_READ_COMMAND~. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.16 + virtual function void set_read(); + set_command(UVM_TLM_READ_COMMAND); + endfunction + + // Function -- NODOCS -- is_write + // + // Returns true if the current value of the variable + // is ~UVM_TLM_WRITE_COMMAND~. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.17 + virtual function bit is_write(); + return (m_command == UVM_TLM_WRITE_COMMAND); + endfunction + + // Function -- NODOCS -- set_write + // + // Set the current value of the variable + // to ~UVM_TLM_WRITE_COMMAND~. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.18 + virtual function void set_write(); + set_command(UVM_TLM_WRITE_COMMAND); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.20 + virtual function void set_address(bit [63:0] addr); + m_address = addr; + endfunction + + // Function -- NODOCS -- get_address + // + // Get the value of the variable + + virtual function bit [63:0] get_address(); + return m_address; + endfunction + + // Function -- NODOCS -- get_data + // + // Return the value of the array + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.21 + virtual function void get_data (output byte unsigned p []); + p = m_data; + endfunction + + // Function -- NODOCS -- set_data + // + // Set the value of the array + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.22 + virtual function void set_data(ref byte unsigned p []); + m_data = p; + endfunction + + // Function -- NODOCS -- get_data_length + // + // Return the current size of the array + + virtual function int unsigned get_data_length(); + return m_length; + endfunction + + // Function -- NODOCS -- set_data_length + // Set the value of the + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.24 + virtual function void set_data_length(int unsigned length); + m_length = length; + endfunction + + // Function -- NODOCS -- get_streaming_width + // + // Get the value of the array + + virtual function int unsigned get_streaming_width(); + return m_streaming_width; + endfunction + + + // Function -- NODOCS -- set_streaming_width + // + // Set the value of the array + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.26 + virtual function void set_streaming_width(int unsigned width); + m_streaming_width = width; + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.27 + virtual function void get_byte_enable(output byte unsigned p[]); + p = m_byte_enable; + endfunction + + // Function -- NODOCS -- set_byte_enable + // + // Set the value of the array + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.28 + virtual function void set_byte_enable(ref byte unsigned p[]); + m_byte_enable = p; + endfunction + + // Function -- NODOCS -- get_byte_enable_length + // + // Return the current size of the array + + virtual function int unsigned get_byte_enable_length(); + return m_byte_enable_length; + endfunction + + // Function -- NODOCS -- set_byte_enable_length + // + // Set the size of the array + // i.e. .size() + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.30 + virtual function void set_byte_enable_length(int unsigned length); + m_byte_enable_length = length; + endfunction + + // Function -- NODOCS -- set_dmi_allowed + // + // DMI hint. Set the internal flag to allow dmi access + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.31 + virtual function void set_dmi_allowed(bit dmi); + m_dmi = dmi; + endfunction + + // Function -- NODOCS -- is_dmi_allowed + // + // DMI hint. Query the internal flag if allowed dmi access + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.32 + virtual function bit is_dmi_allowed(); + return m_dmi; + endfunction + + // Function -- NODOCS -- get_response_status + // + // Return the current value of the variable + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.33 + virtual function uvm_tlm_response_status_e get_response_status(); + return m_response_status; + endfunction + + // Function -- NODOCS -- set_response_status + // + // Set the current value of the variable + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.34 + virtual function void set_response_status(uvm_tlm_response_status_e status); + m_response_status = status; + endfunction + + // Function -- NODOCS -- is_response_ok + // + // Return TRUE if the current value of the variable + // is ~UVM_TLM_OK_RESPONSE~ + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.35 + virtual function bit is_response_ok(); + return (int'(m_response_status) > 0); + endfunction + + // Function -- NODOCS -- is_response_error + // + // Return TRUE if the current value of the variable + // is not ~UVM_TLM_OK_RESPONSE~ + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.36 + virtual function bit is_response_error(); + return !is_response_ok(); + endfunction + + // Function -- NODOCS -- get_response_string + // + // Return the current value of the variable + // as a string + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.37 + virtual function string get_response_string(); + + case(m_response_status) + UVM_TLM_OK_RESPONSE : return "OK"; + UVM_TLM_INCOMPLETE_RESPONSE : return "INCOMPLETE"; + UVM_TLM_GENERIC_ERROR_RESPONSE : return "GENERIC_ERROR"; + UVM_TLM_ADDRESS_ERROR_RESPONSE : return "ADDRESS_ERROR"; + UVM_TLM_COMMAND_ERROR_RESPONSE : return "COMMAND_ERROR"; + UVM_TLM_BURST_ERROR_RESPONSE : return "BURST_ERROR"; + UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE : return "BYTE_ENABLE_ERROR"; + endcase + + // we should never get here + return "UNKNOWN_RESPONSE"; + + endfunction + + //-------------------------------------------------------------------- + // Group -- NODOCS -- Extensions Mechanism + // + //-------------------------------------------------------------------- + + // Function -- NODOCS -- set_extension + // + // Add an instance-specific extension. Only one instance of any given + // extension type is allowed. If there is an existing extension + // instance of the type of ~ext~, ~ext~ replaces it and its handle + // is returned. Otherwise, ~null~ is returned. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.41 + function uvm_tlm_extension_base set_extension(uvm_tlm_extension_base ext); + uvm_tlm_extension_base ext_handle = ext.get_type_handle(); + if(!m_extensions.exists(ext_handle)) + set_extension = null; + else + set_extension = m_extensions[ext_handle]; + m_extensions[ext_handle] = ext; + endfunction + + + // Function -- NODOCS -- get_num_extensions + // + // Return the current number of instance specific extensions. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.39 + function int get_num_extensions(); + return m_extensions.num(); + endfunction: get_num_extensions + + + // Function -- NODOCS -- get_extension + // + // Return the instance specific extension bound under the specified key. + // If no extension is bound under that key, ~null~ is returned. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.40 + function uvm_tlm_extension_base get_extension(uvm_tlm_extension_base ext_handle); + if(!m_extensions.exists(ext_handle)) + return null; + return m_extensions[ext_handle]; + endfunction + + + // Function -- NODOCS -- clear_extension + // + // Remove the instance-specific extension bound under the specified key. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.42 + function void clear_extension(uvm_tlm_extension_base ext_handle); + if(m_extensions.exists(ext_handle)) + m_extensions.delete(ext_handle); + else + `uvm_info("GP_EXT", $sformatf("Unable to find extension to clear"), UVM_MEDIUM) + endfunction + + + // Function -- NODOCS -- clear_extensions + // + // Remove all instance-specific extensions + + // @uvm-ieee 1800.2-2017 auto 12.3.4.2.43 + function void clear_extensions(); + m_extensions.delete(); + endfunction + + + // Function -- NODOCS -- pre_randomize() + // Prepare this class instance for randomization + // + function void pre_randomize(); + int i; + m_rand_exts = new [m_extensions.num()]; + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = ext_; + m_rand_exts[i++] = m_extensions[ext]; + end + endfunction + + // Function -- NODOCS -- post_randomize() + // Clean-up this class instance after randomization + // + function void post_randomize(); + m_rand_exts.delete(); + endfunction +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_gp +// +// This typedef provides a short, more convenient name for the +// type. +//---------------------------------------------------------------------- + +typedef uvm_tlm_generic_payload uvm_tlm_gp; + + + +// @uvm-ieee 1800.2-2017 auto 12.3.4.4.1 +virtual class uvm_tlm_extension_base extends uvm_object; + + + // @uvm-ieee 1800.2-2017 auto 12.3.4.4.3 + function new(string name = ""); + super.new(name); + endfunction + + // Function -- NODOCS -- get_type_handle + // + // An interface to polymorphically retrieve a handle that uniquely + // identifies the type of the sub-class + + // @uvm-ieee 1800.2-2017 auto 12.3.4.4.4 + pure virtual function uvm_tlm_extension_base get_type_handle(); + + // Function -- NODOCS -- get_type_handle_name + // + // An interface to polymorphically retrieve the name that uniquely + // identifies the type of the sub-class + + // @uvm-ieee 1800.2-2017 auto 12.3.4.4.5 + pure virtual function string get_type_handle_name(); + + virtual function void do_copy(uvm_object rhs); + super.do_copy(rhs); + endfunction + + // Function -- NODOCS -- create + // + + virtual function uvm_object create (string name=""); + return null; + endfunction + +endclass + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_extension +// +// UVM TLM extension class. The class is parameterized with arbitrary type +// which represents the type of the extension. An instance of the +// generic payload can contain one extension object of each type; it +// cannot contain two instances of the same extension type. +// +// The extension type can be identified using the +// method. +// +// To implement a generic payload extension, simply derive a new class +// from this class and specify the name of the derived class as the +// extension parameter. +// +//| +//| class my_ID extends uvm_tlm_extension#(my_ID); +//| int ID; +//| +//| `uvm_object_utils_begin(my_ID) +//| `uvm_field_int(ID, UVM_ALL_ON) +//| `uvm_object_utils_end +//| +//| function new(string name = "my_ID"); +//| super.new(name); +//| endfunction +//| endclass +//| + +// @uvm-ieee 1800.2-2017 auto 12.3.4.5.1 +class uvm_tlm_extension #(type T=int) extends uvm_tlm_extension_base; + + typedef uvm_tlm_extension#(T) this_type; + + local static this_type m_my_tlm_ext_type = ID(); + + // Function -- NODOCS -- new + // + // creates a new extension object. + + // @uvm-ieee 1800.2-2017 auto 12.3.4.5.3 + function new(string name=""); + super.new(name); + endfunction + + // Function -- NODOCS -- ID() + // + // Return the unique ID of this UVM TLM extension type. + // This method is used to identify the type of the extension to retrieve + // from a instance, + // using the method. + // + static function this_type ID(); + if (m_my_tlm_ext_type == null) + m_my_tlm_ext_type = new(); + return m_my_tlm_ext_type; + endfunction + + virtual function uvm_tlm_extension_base get_type_handle(); + return ID(); + endfunction + + virtual function string get_type_handle_name(); + return `uvm_typename(T); + endfunction + + virtual function uvm_object create (string name=""); + return null; + endfunction + +endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_ifs.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_ifs.svh new file mode 100644 index 0000000000..fcef259a44 --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_ifs.svh @@ -0,0 +1,185 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//---------------------------------------------------------------------- + +// File -- NODOCS -- UVM TLM 2 Types +typedef class uvm_time; + +// Enum -- NODOCS -- uvm_tlm_phase_e +// +// Nonblocking transport synchronization state values between +// an initiator and a target. +// +// UNINITIALIZED_PHASE - Defaults for constructor +// BEGIN_REQ - Beginning of request phase +// END_REQ - End of request phase +// BEGIN_RESP - Beginning of response phase +// END_RESP - End of response phase + +typedef enum + { + UNINITIALIZED_PHASE, + BEGIN_REQ, + END_REQ, + BEGIN_RESP, + END_RESP + } uvm_tlm_phase_e; + +// Enum -- NODOCS -- uvm_tlm_sync_e +// +// Pre-defined phase state values for the nonblocking transport +// Base Protocol between an initiator and a target. +// +// UVM_TLM_ACCEPTED - Transaction has been accepted +// UVM_TLM_UPDATED - Transaction has been modified +// UVM_TLM_COMPLETED - Execution of transaction is complete + +typedef enum + { + UVM_TLM_ACCEPTED, + UVM_TLM_UPDATED, + UVM_TLM_COMPLETED + } uvm_tlm_sync_e; + +// MACRO -- NODOCS -- `UVM_TLM_TASK_ERROR +// +// Defines Not-Yet-Implemented UVM TLM tasks +`define UVM_TLM_TASK_ERROR "TLM-2 interface task not implemented" + +// MACRO -- NODOCS -- `UVM_TLM_FUNCTION_ERROR +// +// Defines Not-Yet-Implemented UVM TLM functions +`define UVM_TLM_FUNCTION_ERROR "UVM TLM 2 interface function not implemented" + +// +// Class -- NODOCS -- uvm_tlm_if +// +// Base class type to define the transport functions. +// +// - +// +// - +// +// - +// + +// @uvm-ieee 1800.2-2017 auto 12.3.2.1 +class uvm_tlm_if #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e); + //---------------------------------------------------------------------- + // Group -- NODOCS -- tlm transport methods + // + // Each of the interface methods take a handle to the transaction to be + // transported and a reference argument for the delay. In addition, the + // nonblocking interfaces take a reference argument for the phase. + // + + //---------------------------------------------------------------------- + // Function -- NODOCS -- nb_transport_fw + // + // Forward path call. + // The first call to this method for a transaction marks the initial timing point. + // Every call to this method may mark a timing point in the execution of the + // transaction. The timing annotation argument allows the timing points + // to be offset from the simulation times at which the forward path is used. + // The final timing point of a transaction may be marked by a call + // to or a return from this or subsequent call to + // nb_transport_fw. + // + // See + // for more details on the semantics and rules of the nonblocking + // transport interface. + + // @uvm-ieee 1800.2-2017 auto 12.3.2.2.1 + // @uvm-ieee 1800.2-2017 auto 12.3.5.3 + virtual function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + `uvm_error("nb_transport_fw", `UVM_TLM_FUNCTION_ERROR) + return UVM_TLM_ACCEPTED; + endfunction + + // Function -- NODOCS -- nb_transport_bw + // + // Implementation of the backward path. + // This function MUST be implemented in the INITIATOR component class. + // + // Every call to this method may mark a timing point, including the final + // timing point, in the execution of the transaction. + // The timing annotation argument allows the timing point + // to be offset from the simulation times at which the backward path is used. + // The final timing point of a transaction may be marked by a call + // to or a return from this or subsequent call to + // nb_transport_bw. + // + // See + // for more details on the semantics and rules of the nonblocking + // transport interface. + // + // Example: + // + //| class master extends uvm_component; + // uvm_tlm_nb_initiator_socket #(trans, uvm_tlm_phase_e, this_t) initiator_socket; + //| ... + //| function void build_phase(uvm_phase phase); + // initiator_socket = new("initiator_socket", this, this); + //| endfunction + //| + //| function uvm_tlm_sync_e nb_transport_bw(ref trans t, + //| ref uvm_tlm_phase_e p, + //| input uvm_tlm_time delay); + //| transaction = t; + //| state = p; + //| return UVM_TLM_ACCEPTED; + //| endfunction + //| + //| ... + //| endclass + + // @uvm-ieee 1800.2-2017 auto 12.3.2.2.2 + virtual function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + `uvm_error("nb_transport_bw", `UVM_TLM_FUNCTION_ERROR) + return UVM_TLM_ACCEPTED; + endfunction + + // Function -- NODOCS -- b_transport + // + // Execute a blocking transaction. Once this method returns, + // the transaction is assumed to have been executed. Whether + // that execution is successful or not must be indicated by the + // transaction itself. + // + // The callee may modify or update the transaction object, subject + // to any constraints imposed by the transaction class. The + // initiator may re-use a transaction object from one call to + // the next and across calls to b_transport(). + // + // The call to b_transport shall mark the first timing point of the + // transaction. The return from b_transport shall mark the final + // timing point of the transaction. The timing annotation argument + // allows the timing points to be offset from the simulation times + // at which the task call and return are executed. + + // @uvm-ieee 1800.2-2017 auto 12.3.2.2.3 + virtual task b_transport(T t, uvm_tlm_time delay); + `uvm_error("b_transport", `UVM_TLM_TASK_ERROR) + endtask + +endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_imps.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_imps.svh new file mode 100644 index 0000000000..45061dc8bc --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_imps.svh @@ -0,0 +1,208 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM TLM 2 imps (interface implementations) +// +// This section defines the implementation classes for connecting UVM TLM 2 +// interfaces. +// +// UVM TLM imps bind a UVM TLM interface with the object that contains the +// interface implementation. +// In addition to the transaction type and the phase type, the imps +// are parameterized with the type of the object that will provide the +// implementation. Most often this will be the type of the component +// where the imp resides. The constructor of the imp takes as an argument +// an object of type IMP and installs it as the implementation object. +// Most often the imp constructor argument is "this". +//---------------------------------------------------------------------- + +//-------------------------- +// Group -- NODOCS -- IMP binding macros +//-------------------------- + +// Macro -- NODOCS -- `UVM_TLM_NB_TRANSPORT_FW_IMP +// +// The macro wraps the forward path call function nb_transport_fw() +// +// The first call to this method for a transaction marks the initial timing point. +// Every call to this method may mark a timing point in the execution of the +// transaction. The timing annotation argument allows the timing points +// to be offset from the simulation times at which the forward path is used. +// The final timing point of a transaction may be marked by a call +// to nb_transport_bw() within <`UVM_TLM_NB_TRANSPORT_BW_IMP> or a return from this +// or subsequent call to nb_transport_fw(). +// +// See +// for more details on the semantics and rules of the nonblocking +// transport interface. + +`define UVM_TLM_NB_TRANSPORT_FW_IMP(imp, T, P, t, p, delay) \ + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); \ + if (delay == null) begin \ + `uvm_error("UVM/TLM/NULLDELAY", \ + {get_full_name(), \ + ".nb_transport_fw() called with 'null' delay"}) \ + return UVM_TLM_COMPLETED; \ + end \ + return imp.nb_transport_fw(t, p, delay); \ + endfunction + + +// Macro -- NODOCS -- `UVM_TLM_NB_TRANSPORT_BW_IMP +// +// +// Implementation of the backward path. +// The macro wraps the function called nb_transport_bw(). +// This function MUST be implemented in the INITIATOR component class. +// +// Every call to this method may mark a timing point, including the final +// timing point, in the execution of the transaction. +// The timing annotation argument allows the timing point +// to be offset from the simulation times at which the backward path is used. +// The final timing point of a transaction may be marked by a call +// to nb_transport_fw() within <`UVM_TLM_NB_TRANSPORT_FW_IMP> or a return from +// this or subsequent call to nb_transport_bw(). +// +// See +// for more details on the semantics and rules of the nonblocking +// transport interface. +// +// Example: +// +//| class master extends uvm_component; +//| uvm_tlm_nb_initiator_socket +//| #(trans, uvm_tlm_phase_e, this_t) initiator_socket; +//| +//| function void build_phase(uvm_phase phase); +//| initiator_socket = new("initiator_socket", this, this); +//| endfunction +//| +//| function uvm_tlm_sync_e nb_transport_bw(trans t, +//| ref uvm_tlm_phase_e p, +//| input uvm_tlm_time delay); +//| transaction = t; +//| state = p; +//| return UVM_TLM_ACCEPTED; +//| endfunction +//| +//| ... +//| endclass + +`define UVM_TLM_NB_TRANSPORT_BW_IMP(imp, T, P, t, p, delay) \ + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); \ + if (delay == null) begin \ + `uvm_error("UVM/TLM/NULLDELAY", \ + {get_full_name(), \ + ".nb_transport_bw() called with 'null' delay"}) \ + return UVM_TLM_COMPLETED; \ + end \ + return imp.nb_transport_bw(t, p, delay); \ + endfunction + + +// Macro -- NODOCS -- `UVM_TLM_B_TRANSPORT_IMP +// +// The macro wraps the function b_transport() +// Execute a blocking transaction. Once this method returns, +// the transaction is assumed to have been executed. Whether +// that execution is successful or not must be indicated by the +// transaction itself. +// +// The callee may modify or update the transaction object, subject +// to any constraints imposed by the transaction class. The +// initiator may re-use a transaction object from one call to +// the next and across calls to b_transport(). +// +// The call to b_transport shall mark the first timing point of the +// transaction. The return from b_transport() shall mark the final +// timing point of the transaction. The timing annotation argument +// allows the timing points to be offset from the simulation times +// at which the task call and return are executed. + +`define UVM_TLM_B_TRANSPORT_IMP(imp, T, t, delay) \ + task b_transport(T t, uvm_tlm_time delay); \ + if (delay == null) begin \ + `uvm_error("UVM/TLM/NULLDELAY", \ + {get_full_name(), \ + ".b_transport() called with 'null' delay"}) \ + return; \ + end \ + imp.b_transport(t, delay); \ + endtask + + + +//--------------------------- +// Group -- NODOCS -- IMP binding classes +//--------------------------- + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_transport_imp +// +// Used like exports, except an additional class parameter specifies +// the type of the implementation object. When the +// imp is instantiated the implementation object is bound. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.8.1 +class uvm_tlm_b_transport_imp #(type T=uvm_tlm_generic_payload, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T)); + `UVM_IMP_COMMON(`UVM_TLM_B_MASK, "uvm_tlm_b_transport_imp", IMP) + `UVM_TLM_B_TRANSPORT_IMP(m_imp, T, t, delay) +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_transport_fw_imp +// +// Used like exports, except an additional class parameter specifies +// the type of the implementation object. When the +// imp is instantiated the implementation object is bound. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.8.2 +class uvm_tlm_nb_transport_fw_imp #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + `UVM_IMP_COMMON(`UVM_TLM_NB_FW_MASK, "uvm_tlm_nb_transport_fw_imp", IMP) + `UVM_TLM_NB_TRANSPORT_FW_IMP(m_imp, T, P, t, p, delay) +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_transport_bw_imp +// +// Used like exports, except an additional class parameter specifies +// the type of the implementation object. When the +// imp is instantiated the implementation object is bound. +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.8.3 +class uvm_tlm_nb_transport_bw_imp #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + `UVM_IMP_COMMON(`UVM_TLM_NB_BW_MASK, "uvm_tlm_nb_transport_bw_imp", IMP) + `UVM_TLM_NB_TRANSPORT_BW_IMP(m_imp, T, P, t, p, delay) +endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_ports.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_ports.svh new file mode 100644 index 0000000000..d0391d7865 --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_ports.svh @@ -0,0 +1,79 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 NVIDIA Corporation +// Copyright 2014 Cisco Systems, 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM TLM 2 ports +// +// The following defines UVM TLM 2 port classes. +// +//---------------------------------------------------------------------- + +// class -- NODOCS -- uvm_tlm_b_transport_port +// +// Class providing the blocking transport port. +// The port can be bound to one export. +// There is no backward path for the blocking transport. + +// @uvm-ieee 1800.2-2017 auto 12.3.6.1 +class uvm_tlm_b_transport_port #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + `UVM_PORT_COMMON(`UVM_TLM_B_MASK, "uvm_tlm_b_transport_port") + `UVM_TLM_B_TRANSPORT_IMP(this.m_if, T, t, delay) +endclass + + +// class -- NODOCS -- uvm_tlm_nb_transport_fw_port +// +// Class providing the non-blocking backward transport port. +// Transactions received from the producer, on the forward path, are +// sent back to the producer on the backward path using this +// non-blocking transport port. +// The port can be bound to one export. +// + +// @uvm-ieee 1800.2-2017 auto 12.3.6.2 +class uvm_tlm_nb_transport_fw_port #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + `UVM_PORT_COMMON(`UVM_TLM_NB_FW_MASK, "uvm_tlm_nb_transport_fw_port") + `UVM_TLM_NB_TRANSPORT_FW_IMP(this.m_if, T, P, t, p, delay) +endclass + +// class -- NODOCS -- uvm_tlm_nb_transport_bw_port +// +// Class providing the non-blocking backward transport port. +// Transactions received from the producer, on the forward path, are +// sent back to the producer on the backward path using this +// non-blocking transport port +// The port can be bound to one export. +// + +// @uvm-ieee 1800.2-2017 auto 12.3.6.3 +class uvm_tlm_nb_transport_bw_port #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + + // Function -- NODOCS -- new + `UVM_PORT_COMMON(`UVM_TLM_NB_BW_MASK, "uvm_tlm_nb_transport_bw_port") + `UVM_TLM_NB_TRANSPORT_BW_IMP(this.m_if, T, P, t, p, delay) +endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_sockets.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_sockets.svh new file mode 100644 index 0000000000..c89d14b440 --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_sockets.svh @@ -0,0 +1,424 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2010-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM TLM Sockets +// +// Each uvm_tlm_*_socket class is derived from a corresponding +// uvm_tlm_*_socket_base class. The base class contains most of the +// implementation of the class, The derived classes (in this file) +// contain the connection semantics. +// +// Sockets come in several flavors: Each socket is either an initiator or a +// target, a pass-through or a terminator. Further, any particular socket +// implements either the blocking interfaces or the nonblocking interfaces. +// Terminator sockets are used on initiators and targets as well as +// interconnect components as shown in the figure above. Pass-through +// sockets are used to enable connections to cross hierarchical boundaries. +// +// There are eight socket types: the cross of blocking and nonblocking, +// pass-through and termination, target and initiator +// +// Sockets are specified based on what they are (IS-A) +// and what they contains (HAS-A). +// IS-A and HAS-A are types of object relationships. +// IS-A refers to the inheritance relationship and +// HAS-A refers to the ownership relationship. +// For example if you say D is a B that means that D is derived from base B. +// If you say object A HAS-A B that means that B is a member of A. +//---------------------------------------------------------------------- + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_initiator_socket +// +// IS-A forward port; has no backward path except via the payload +// contents +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.2.1 +class uvm_tlm_b_initiator_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_initiator_socket_base #(T); + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.2.3 + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.2.4 + function void connect(this_type provider); + + uvm_tlm_b_passthrough_initiator_socket_base #(T) initiator_pt_socket; + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + + uvm_component c; + + super.connect(provider); + + if($cast(initiator_pt_socket, provider) || + $cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + + c = get_comp(); + `uvm_error_context(get_type_name(), + "type mismatch in connect -- connection cannot be completed", c) + + endfunction + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_target_socket +// +// IS-A forward imp; has no backward path except via the payload +// contents. +// +// The component instantiating this socket must implement +// a b_transport() method with the following signature +// +//| task b_transport(T t, uvm_tlm_time delay); +// +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.1.1 +class uvm_tlm_b_target_socket #(type IMP=int, + type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_target_socket_base #(T); + + local IMP m_imp; + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.1.3 + function new (string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(m_imp, parent); + else m_imp = imp; + if (m_imp == null) + `uvm_error("UVM/TLM2/NOIMP", {"b_target socket ", name, + " has no implementation"}) + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.1.4 + function void connect(this_type provider); + + uvm_component c; + + super.connect(provider); + + c = get_comp(); + `uvm_error_context(get_type_name(), + "You cannot call connect() on a target termination socket", c) + endfunction + + `UVM_TLM_B_TRANSPORT_IMP(m_imp, T, t, delay) + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_initiator_socket +// +// IS-A forward port; HAS-A backward imp +// +// The component instantiating this socket must implement +// a nb_transport_bw() method with the following signature +// +//| function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); +// +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.4.1 +class uvm_tlm_nb_initiator_socket #(type IMP=int, + type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_initiator_socket_base #(T,P); + + uvm_tlm_nb_transport_bw_imp #(T,P,IMP) bw_imp; + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.4.3 + function new(string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(imp, parent); + if (imp == null) + `uvm_error("UVM/TLM2/NOIMP", {"nb_initiator socket ", name, + " has no implementation"}) + bw_imp = new("bw_imp", imp); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.4.4 + function void connect(this_type provider); + + uvm_tlm_nb_passthrough_initiator_socket_base #(T,P) initiator_pt_socket; + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + + uvm_component c; + + super.connect(provider); + + if($cast(initiator_pt_socket, provider)) begin + initiator_pt_socket.bw_export.connect(bw_imp); + return; + end + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_imp); + return; + end + + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_imp); + return; + end + + c = get_comp(); + `uvm_error_context(get_type_name(), + "type mismatch in connect -- connection cannot be completed", c) + + endfunction + +endclass + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_target_socket +// +// IS-A forward imp; HAS-A backward port +// +// The component instantiating this socket must implement +// a nb_transport_fw() method with the following signature +// +//| function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); +// +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.3.1 +class uvm_tlm_nb_target_socket #(type IMP=int, + type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_target_socket_base #(T,P); + + local IMP m_imp; + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.3.3 + function new (string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(m_imp, parent); + else m_imp = imp; + bw_port = new("bw_port", get_comp()); + if (m_imp == null) + `uvm_error("UVM/TLM2/NOIMP", {"nb_target socket ", name, + " has no implementation"}) + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.3.4 + function void connect(this_type provider); + + uvm_component c; + + super.connect(provider); + + c = get_comp(); + `uvm_error_context(get_type_name(), + "You cannot call connect() on a target termination socket", c) + endfunction + + `UVM_TLM_NB_TRANSPORT_FW_IMP(m_imp, T, P, t, p, delay) + +endclass + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_passthrough_initiator_socket +// +// IS-A forward port; +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.7 +class uvm_tlm_b_passthrough_initiator_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_passthrough_initiator_socket_base #(T); + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + + // Function -- NODOCS -- connect + // + // Connect this socket to the specified + function void connect(this_type provider); + + uvm_tlm_b_passthrough_initiator_socket_base #(T) initiator_pt_socket; + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + + uvm_component c; + + super.connect(provider); + + if($cast(initiator_pt_socket, provider) || + $cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + + c = get_comp(); + `uvm_error_context(get_type_name(), "type mismatch in connect -- connection cannot be completed", c) + + endfunction + +endclass + + +// @uvm-ieee 1800.2-2017 auto 12.3.5.8 +class uvm_tlm_b_passthrough_target_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_passthrough_target_socket_base #(T); + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + + // Function -- NODOCS -- connect + // + // Connect this socket to the specified + function void connect(this_type provider); + + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + + uvm_component c; + + super.connect(provider); + + if($cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + + c = get_comp(); + `uvm_error_context(get_type_name(), + "type mismatch in connect -- connection cannot be completed", c) + endfunction + +endclass + + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_passthrough_initiator_socket +// +// IS-A forward port; HAS-A backward export +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.5 +class uvm_tlm_nb_passthrough_initiator_socket #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_passthrough_initiator_socket_base #(T,P); + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + + // Function -- NODOCS -- connect + // + // Connect this socket to the specified + function void connect(this_type provider); + + uvm_tlm_nb_passthrough_initiator_socket_base #(T,P) initiator_pt_socket; + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + + uvm_component c; + + super.connect(provider); + + if($cast(initiator_pt_socket, provider)) begin + bw_export.connect(initiator_pt_socket.bw_export); + return; + end + + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_export); + return; + end + + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_export); + return; + end + + c = get_comp(); + `uvm_error_context(get_type_name(), + "type mismatch in connect -- connection cannot be completed", c) + + endfunction + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_passthrough_target_socket +// +// IS-A forward export; HAS-A backward port +//---------------------------------------------------------------------- + +// @uvm-ieee 1800.2-2017 auto 12.3.5.6.1 +class uvm_tlm_nb_passthrough_target_socket #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_passthrough_target_socket_base #(T,P); + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + + + // @uvm-ieee 1800.2-2017 auto 12.3.5.6.2 + function void connect(this_type provider); + + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + + uvm_component c; + + super.connect(provider); + + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_port); + return; + end + + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_port); + return; + end + + c = get_comp(); + `uvm_error_context(get_type_name(), + "type mismatch in connect -- connection cannot be completed", c) + + endfunction + +endclass + diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm2_sockets_base.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm2_sockets_base.svh new file mode 100644 index 0000000000..f7b4071a65 --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm2_sockets_base.svh @@ -0,0 +1,219 @@ +//---------------------------------------------------------------------- +// Copyright 2010-2011 Mentor Graphics Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2011-2018 Cadence Design Systems, Inc. +// Copyright 2015-2018 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. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Title -- NODOCS -- UVM TLM Socket Base Classes +// +// A collection of base classes, one for each socket type. The reason +// for having a base class for each socket is that all the socket (base) +// types must be known before connect is defined. Socket connection +// semantics are provided in the derived classes, which are user +// visible. +// +// Termination Sockets - A termination socket must be the terminus +// of every UVM TLM path. A transaction originates with an initiator socket +// and ultimately ends up in a target socket. There may be zero or more +// pass-through sockets between initiator and target. +// +// Pass-through Sockets - Pass-through initiators are ports and contain +// exports for instance IS-A port and HAS-A export. Pass-through targets +// are the opposite, they are exports and contain ports. +//---------------------------------------------------------------------- + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_target_socket_base +// +// IS-A forward imp; has no backward path except via the payload +// contents. +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_b_target_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + + function new (string name, uvm_component parent); + super.new (name, parent, UVM_IMPLEMENTATION, 1, 1); + m_if_mask = `UVM_TLM_B_MASK; + endfunction + + `UVM_TLM_GET_TYPE_NAME("uvm_tlm_b_target_socket") + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_initiator_socket_base +// +// IS-A forward port; has no backward path except via the payload +// contents +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_b_initiator_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + + `UVM_PORT_COMMON(`UVM_TLM_B_MASK, "uvm_tlm_b_initiator_socket") + `UVM_TLM_B_TRANSPORT_IMP(this.m_if, T, t, delay) + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_target_socket_base +// +// IS-A forward imp; HAS-A backward port +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_nb_target_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + + uvm_tlm_nb_transport_bw_port #(T,P) bw_port; + + function new (string name, uvm_component parent); + super.new (name, parent, UVM_IMPLEMENTATION, 1, 1); + m_if_mask = `UVM_TLM_NB_FW_MASK; + endfunction + + `UVM_TLM_GET_TYPE_NAME("uvm_tlm_nb_target_socket") + + `UVM_TLM_NB_TRANSPORT_BW_IMP(bw_port, T, P, t, p, delay) + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_initiator_socket_base +// +// IS-A forward port; HAS-A backward imp +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_nb_initiator_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + + function new (string name, uvm_component parent); + super.new (name, parent, UVM_PORT, 1, 1); + m_if_mask = `UVM_TLM_NB_FW_MASK; + endfunction + + `UVM_TLM_GET_TYPE_NAME("uvm_tlm_nb_initiator_socket") + + `UVM_TLM_NB_TRANSPORT_FW_IMP(this.m_if, T, P, t, p, delay) + +endclass + + + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_passthrough_initiator_socket_base +// +// IS-A forward port; HAS-A backward export +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_nb_passthrough_initiator_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + + uvm_tlm_nb_transport_bw_export #(T,P) bw_export; + + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = `UVM_TLM_NB_FW_MASK; + bw_export = new("bw_export", get_comp()); + endfunction + + `UVM_TLM_GET_TYPE_NAME("uvm_tlm_nb_passthrough_initiator_socket") + + `UVM_TLM_NB_TRANSPORT_FW_IMP(this.m_if, T, P, t, p, delay) + `UVM_TLM_NB_TRANSPORT_BW_IMP(bw_export, T, P, t, p, delay) + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_nb_passthrough_target_socket_base +// +// IS-A forward export; HAS-A backward port +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_nb_passthrough_target_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + + uvm_tlm_nb_transport_bw_port #(T,P) bw_port; + + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = `UVM_TLM_NB_FW_MASK; + bw_port = new("bw_port", get_comp()); + endfunction + + `UVM_TLM_GET_TYPE_NAME("uvm_tlm_nb_passthrough_target_socket") + + `UVM_TLM_NB_TRANSPORT_FW_IMP(this.m_if, T, P, t, p, delay) + `UVM_TLM_NB_TRANSPORT_BW_IMP(bw_port, T, P, t, p, delay) + +endclass + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_passthrough_initiator_socket_base +// +// IS-A forward port +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_b_passthrough_initiator_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + + `UVM_PORT_COMMON(`UVM_TLM_B_MASK, "uvm_tlm_b_passthrough_initiator_socket") + `UVM_TLM_B_TRANSPORT_IMP(this.m_if, T, t, delay) + +endclass + + +//---------------------------------------------------------------------- +// Class -- NODOCS -- uvm_tlm_b_passthrough_target_socket_base +// +// IS-A forward export +//---------------------------------------------------------------------- +`ifndef UVM_ENABLE_DEPRECATED_API +virtual +`endif +class uvm_tlm_b_passthrough_target_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + + `UVM_EXPORT_COMMON(`UVM_TLM_B_MASK, "uvm_tlm_b_passthrough_target_socket") + `UVM_TLM_B_TRANSPORT_IMP(this.m_if, T, t, delay) + + endclass diff --git a/test_regress/t/t_uvm/tlm2/uvm_tlm_time.svh b/test_regress/t/t_uvm/tlm2/uvm_tlm_time.svh new file mode 100644 index 0000000000..cdb94ce4dd --- /dev/null +++ b/test_regress/t/t_uvm/tlm2/uvm_tlm_time.svh @@ -0,0 +1,347 @@ +//---------------------------------------------------------------------- +// Copyright 2011-2014 Mentor Graphics Corporation +// Copyright 2014 Semifore +// Copyright 2014 Intel Corporation +// Copyright 2010-2018 Synopsys, Inc. +// Copyright 2011-2018 Cadence Design Systems, Inc. +// Copyright 2014-2018 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. +//---------------------------------------------------------------------- + +// CLASS -- NODOCS -- uvm_tlm_time +// Canonical time type that can be used in different timescales +// +// This time type is used to represent time values in a canonical +// form that can bridge initiators and targets located in different +// timescales and time precisions. +// +// For a detailed explanation of the purpose for this class, +// see . +// + +// @uvm-ieee 1800.2-2017 auto 5.6.1 +class uvm_time; + + static local real m_resolution = 1.0e-12; // ps by default + local real m_res; + local time m_time; // Number of 'm_res' time units, + local string m_name; + + // Function -- NODOCS -- set_time_resolution + // Set the default canonical time resolution. + // + // Must be a power of 10. + // When co-simulating with SystemC, it is recommended + // that default canonical time resolution be set to the + // SystemC time resolution. + // + // By default, the default resolution is 1.0e-12 (ps) + // + static function void set_time_resolution(real res); + // Actually, it does not *really* need to be a power of 10. + m_resolution = res; + endfunction + + // Function -- NODOCS -- new + // Create a new canonical time value. + // + // The new value is initialized to 0. + // If a resolution is not specified, + // the default resolution, + // as specified by , + // is used. + // @uvm-ieee 1800.2-2017 auto 5.6.2.1 + function new(string name = "uvm_tlm_time", real res = 0); + m_name = name; + m_res = (res == 0) ? m_resolution : res; + reset(); + endfunction + + + // Function -- NODOCS -- get_name + // Return the name of this instance + // + // @uvm-ieee 1800.2-2017 auto 5.6.2.3 + function string get_name(); + return m_name; + endfunction + + + // Function -- NODOCS -- reset + // Reset the value to 0 + // @uvm-ieee 1800.2-2017 auto 5.6.2.4 + function void reset(); + m_time = 0; + endfunction + + + // Scale a timescaled value to 'm_res' units, + // the specified scale + local function real to_m_res(real t, time scaled, real secs); + // ToDo: Check resolution + return t/real'(scaled) * (secs/m_res); + endfunction + + + // Function -- NODOCS -- get_realtime + // Return the current canonical time value, + // scaled for the caller's timescale + // + // ~scaled~ must be a time literal value that corresponds + // to the number of seconds specified in ~secs~ (1ns by default). + // It must be a time literal value that is greater or equal + // to the current timescale. + // + //| #(delay.get_realtime(1ns)); + //| #(delay.get_realtime(1fs, 1.0e-15)); + // + // @uvm-ieee 1800.2-2017 auto 5.6.2.5 + function real get_realtime(time scaled, real secs = 1.0e-9); + return m_time*real'(scaled) * m_res/secs; + endfunction + + + // Function -- NODOCS -- incr + // Increment the time value by the specified number of scaled time unit + // + // ~t~ is a time value expressed in the scale and precision + // of the caller. + // ~scaled~ must be a time literal value that corresponds + // to the number of seconds specified in ~secs~ (1ns by default). + // It must be a time literal value that is greater or equal + // to the current timescale. + // + //| delay.incr(1.5ns, 1ns); + //| delay.incr(1.5ns, 1ps, 1.0e-12); + // + // @uvm-ieee 1800.2-2017 auto 5.6.2.6 + function void incr(real t, time scaled, real secs = 1.0e-9); + if (t < 0.0) begin + `uvm_error("UVM/TLM/TIMENEG", {"Cannot increment uvm_tlm_time variable ", m_name, " by a negative value"}) + return; + end + if (scaled == 0) begin + `uvm_fatal("UVM/TLM/BADSCALE", + "uvm_tlm_time::incr() called with a scaled time literal that is smaller than the current timescale") + end + + m_time += to_m_res(t, scaled, secs); + endfunction + + + // Function -- NODOCS -- decr + // Decrement the time value by the specified number of scaled time unit + // + // ~t~ is a time value expressed in the scale and precision + // of the caller. + // ~scaled~ must be a time literal value that corresponds + // to the number of seconds specified in ~secs~ (1ns by default). + // It must be a time literal value that is greater or equal + // to the current timescale. + // + //| delay.decr(200ps, 1ns); + // + // @uvm-ieee 1800.2-2017 auto 5.6.2.7 + function void decr(real t, time scaled, real secs); + if (t < 0.0) begin + `uvm_error("UVM/TLM/TIMENEG", {"Cannot decrement uvm_tlm_time variable ", m_name, " by a negative value"}) + return; + end + if (scaled == 0) begin + `uvm_fatal("UVM/TLM/BADSCALE", + "uvm_tlm_time::decr() called with a scaled time literal that is smaller than the current timescale") + end + + m_time -= to_m_res(t, scaled, secs); + + if (m_time < 0.0) begin + `uvm_error("UVM/TLM/TOODECR", {"Cannot decrement uvm_tlm_time variable ", m_name, " to a negative value"}) + reset(); + end + endfunction + + + // Function -- NODOCS -- get_abstime + // Return the current canonical time value, + // in the number of specified time unit, regardless of the + // current timescale of the caller. + // + // ~secs~ is the number of seconds in the desired time unit + // e.g. 1e-9 for nanoseconds. + // + //| $write("%.3f ps\n", delay.get_abstime(1e-12)); + // + // @uvm-ieee 1800.2-2017 auto 5.6.2.8 + function real get_abstime(real secs); + return m_time*m_res/secs; + endfunction + + + // Function -- NODOCS -- set_abstime + // Set the current canonical time value, + // to the number of specified time unit, regardless of the + // current timescale of the caller. + // + // ~secs~ is the number of seconds in the time unit in the value ~t~ + // e.g. 1e-9 for nanoseconds. + // + //| delay.set_abstime(1.5, 1e-12)); + // + // @uvm-ieee 1800.2-2017 auto 5.6.2.9 + function void set_abstime(real t, real secs); + m_time = t*secs/m_res; + endfunction +endclass + +typedef uvm_time uvm_tlm_time; + +// Group -- NODOCS -- Why is this necessary +// +// Integers are not sufficient, on their own, +// to represent time without any ambiguity: +// you need to know the scale of that integer value. +// That scale is information conveyed outside of that integer. +// In SystemVerilog, it is based on the timescale +// that was active when the code was compiled. +// SystemVerilog properly scales time literals, but not integer values. +// That's because it does not know the difference between an integer +// that carries an integer value and an integer that carries a time value. +// The 'time' variables are simply 64-bit integers, +// they are not scaled back and forth to the underlying precision. +// +//| `timescale 1ns/1ps +//| +//| module m(); +//| +//| time t; +//| +//| initial +//| begin +//| #1.5; +//| $write("T=%f ns (1.5)\n", $realtime()); +//| t = 1.5; +//| #t; +//| $write("T=%f ns (3.0)\n", $realtime()); +//| #10ps; +//| $write("T=%f ns (3.010)\n", $realtime()); +//| t = 10ps; +//| #t; +//| $write("T=%f ns (3.020)\n", $realtime()); +//| end +//| endmodule +// +// yields +// +//| T=1.500000 ns (1.5) +//| T=3.500000 ns (3.0) +//| T=3.510000 ns (3.010) +//| T=3.510000 ns (3.020) +// +// Within SystemVerilog, we have to worry about +// - different time scale +// - different time precision +// +// Because each endpoint in a socket +// could be coded in different packages +// and thus be executing under different timescale directives, +// a simple integer cannot be used to exchange time information +// across a socket. +// +// For example +// +//| `timescale 1ns/1ps +//| +//| package a_pkg; +//| +//| class a; +//| function void f(inout time t); +//| t += 10ns; +//| endfunction +//| endclass +//| +//| endpackage +//| +//| +//| `timescale 1ps/1ps +//| +//| program p; +//| +//| import a_pkg::*; +//| +//| time t; +//| +//| initial +//| begin +//| a A = new; +//| A.f(t); +//| #t; +//| $write("T=%0d ps (10,000)\n", $realtime()); +//| end +//| endprogram +// +// yields +// +//| T=10 ps (10,000) +// +// Scaling is needed every time you make a procedural call +// to code that may interpret a time value in a different timescale. +// +// Using the uvm_tlm_time type +// +//| `timescale 1ns/1ps +//| +//| package a_pkg; +//| +//| import uvm_pkg::*; +//| +//| class a; +//| function void f(uvm_tlm_time t); +//| t.incr(10ns, 1ns); +//| endfunction +//| endclass +//| +//| endpackage +//| +//| +//| `timescale 1ps/1ps +//| +//| program p; +//| +//| import uvm_pkg::*; +//| import a_pkg::*; +//| +//| uvm_tlm_time t = new; +//| +//| initial +//| begin +//| a A = new; +//| A.f(t); +//| #(t.get_realtime(1ns)); +//| $write("T=%0d ps (10,000)\n", $realtime()); +//| end +//| endprogram +// +// yields +// +//| T=10000 ps (10,000) +// +// A similar procedure is required when crossing any simulator +// or language boundary, +// such as interfacing between SystemVerilog and SystemC. + + + diff --git a/test_regress/t/t_uvm/uvm.sv b/test_regress/t/t_uvm/uvm.sv new file mode 100644 index 0000000000..fdeae0b96c --- /dev/null +++ b/test_regress/t/t_uvm/uvm.sv @@ -0,0 +1,25 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010-2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2013-2018 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. +//---------------------------------------------------------------------- + +`include "uvm_pkg.sv" \ No newline at end of file diff --git a/test_regress/t/t_uvm/uvm_macros.svh b/test_regress/t/t_uvm/uvm_macros.svh new file mode 100644 index 0000000000..6c38fc6e10 --- /dev/null +++ b/test_regress/t/t_uvm/uvm_macros.svh @@ -0,0 +1,91 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2013 Mentor Graphics Corporation +// Copyright 2010-2014 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010-2018 AMD +// Copyright 2013-2018 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_MACROS_SVH +`define UVM_MACROS_SVH + +// +// Any vendor specific defines go here. +// + +`ifdef MODEL_TECH +`ifndef QUESTA +`define QUESTA +`endif +`endif + +`ifndef UVM_USE_STRING_QUEUE_STREAMING_PACK + `define UVM_STRING_QUEUE_STREAMING_PACK(q) uvm_pkg::m_uvm_string_queue_join(q) +`endif + +`ifndef QUESTA +`define uvm_typename(X) $typename(X) +`else +`define uvm_typename(X) $typename(X,39) +`endif + +`ifdef VCS +`endif + + +// cadence simulators xcelium/inca +`ifndef XCELIUM +`ifdef INCA +`define UVM_XCELIUM +`define UVM_USE_PROCESS_CONTAINER +`endif +`endif +`ifdef XCELIUM +`define UVM_XCELIUM +`define DPI_COMPATIBILITY_VERSION_1800v2005 +`endif + +`define uvm_delay(TIME) #(TIME); + + +`include "macros/uvm_version_defines.svh" +`include "macros/uvm_global_defines.svh" +`include "macros/uvm_message_defines.svh" +`include "macros/uvm_phase_defines.svh" +`include "macros/uvm_printer_defines.svh" +`include "macros/uvm_comparer_defines.svh" +`include "macros/uvm_recorder_defines.svh" +`include "macros/uvm_resource_defines.svh" +`include "macros/uvm_packer_defines.svh" +`include "macros/uvm_copier_defines.svh" +`ifdef UVM_ENABLE_DEPRECATED_API + `include "deprecated/macros/uvm_object_defines.svh" +`else + `include "macros/uvm_object_defines.svh" +`endif +`include "macros/uvm_tlm_defines.svh" +`include "macros/uvm_sequence_defines.svh" +`include "macros/uvm_callback_defines.svh" +`include "macros/uvm_reg_defines.svh" + +`ifdef UVM_ENABLE_DEPRECATED_API +`include "deprecated/macros/uvm_sequence_defines.svh" +`endif + +`endif diff --git a/test_regress/t/t_uvm/uvm_pkg.sv b/test_regress/t/t_uvm/uvm_pkg.sv new file mode 100644 index 0000000000..115a7c9459 --- /dev/null +++ b/test_regress/t/t_uvm/uvm_pkg.sv @@ -0,0 +1,41 @@ +// +//---------------------------------------------------------------------- +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2011 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, 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_PKG_SV +`define UVM_PKG_SV + +`include "uvm_macros.svh" + +package uvm_pkg; + + `include "dpi/uvm_dpi.svh" + `include "base/uvm_base.svh" + `include "dap/uvm_dap.svh" + `include "tlm1/uvm_tlm.svh" + `include "comps/uvm_comps.svh" + `include "seq/uvm_seq.svh" + `include "tlm2/uvm_tlm2.svh" + `include "reg/uvm_reg_model.svh" + +endpackage + +`endif diff --git a/test_regress/t/t_uvm/uvmt_extras.svh b/test_regress/t/t_uvm/uvmt_extras.svh new file mode 100644 index 0000000000..84131d85d3 --- /dev/null +++ b/test_regress/t/t_uvm/uvmt_extras.svh @@ -0,0 +1,19 @@ +`define uvmt_register_cb(T, CB) \ + static function void uvmt_drop_and_reregister_cb(); \ + uvmt_callbacks#(T,CB)::drop_globals(); \ + m_register_cb_``CB = uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`"); \ + endfunction + +class uvmt_queue #(type T=int); + static function void drop_globals(); + uvm_pkg::uvm_queue#(T)::m_global_queue = null; + endfunction +endclass + +class uvmt_callbacks #(type T=uvm_pkg::uvm_object, type CB=uvm_pkg::uvm_callback); + static function void drop_globals(); + uvm_pkg::uvm_callbacks#(T, CB)::m_tw_cb_q.delete(); + uvm_pkg::uvm_callbacks#(T, CB)::m_t_inst = null; + uvm_pkg::uvm_callbacks#(T, CB)::m_inst = null; + endfunction +endclass diff --git a/test_regress/t/t_uvm/uvmt_logs.svh b/test_regress/t/t_uvm/uvmt_logs.svh index 7205d1805c..f758ba28b9 100644 --- a/test_regress/t/t_uvm/uvmt_logs.svh +++ b/test_regress/t/t_uvm/uvmt_logs.svh @@ -86,3 +86,15 @@ function void uvm_report_warning(string id, if (filename != "") $display("(mock) ^ at %s:%0d ", filename, line); endfunction + +function void uvm_report_info(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + $display("(mock) {UVM} INFO: [%s] %s ", id, message); + if (filename != "") + $display("(mock) ^ at %s:%0d ", filename, line); +endfunction diff --git a/test_regress/t/t_uvm_callback.pl b/test_regress/t/t_uvm_callback.pl new file mode 100755 index 0000000000..096f7db1e2 --- /dev/null +++ b/test_regress/t/t_uvm_callback.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--binary", "--timing", + "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "-Wno-CASEINCOMPLETE -Wno-CASTCONST -Wno-SYMRSVDWORD -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC", + "-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream + "-Wno-ZERODLY", # TODO issue #4494, add support", + "-Wno-ENCAPSULATED", + "-It/t_uvm", "-DUVM_REGEX_NO_DPI -DUVM_CMDLINE_NO_DPI -DUVM_NO_DPI -DUVM_HDL_NO_DPI"], + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_uvm_callback.v b/test_regress/t/t_uvm_callback.v new file mode 100644 index 0000000000..a9172693f9 --- /dev/null +++ b/test_regress/t/t_uvm_callback.v @@ -0,0 +1,141 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`include "uvmt_unit.svh" +`include "uvm_pkg.sv" +`include "uvmt_extras.svh" + +import uvm_pkg::*; + +typedef class test_cb; + +class cb_ctx extends uvm_object; + `uvm_register_cb(cb_ctx, test_cb) + `uvmt_register_cb(cb_ctx, test_cb) + + string m_strq[$]; + + function new(string name); super.new(name); endfunction + + function void append_str(string str); + m_strq.push_back(str); + endfunction +endclass + +class test_cb extends uvm_callback; + function new(string name); super.new(name); endfunction + + function void append_str(cb_ctx ctx); + ctx.append_str(get_name()); + endfunction +endclass + +class uvm_callback_testsuite extends uvmt::uvm_testsuite; + cb_ctx m_ctx[string]; + + extern function new(); + + virtual task setup(); + cb_ctx::uvmt_drop_and_reregister_cb(); + m_ctx.delete(); + m_ctx["foo"] = new("foo"); + m_ctx["bar"] = new("bar"); + endtask + + function void add_callback(string ctx_name, test_cb cb); + uvm_callbacks#(cb_ctx, test_cb)::add(m_ctx[ctx_name], cb); + endfunction + + function void delete_callback(string ctx_name, test_cb cb); + uvm_callbacks#(cb_ctx, test_cb)::delete(m_ctx[ctx_name], cb); + endfunction + + + function void do_callbacks(string ctx_name); + `uvm_do_obj_callbacks(cb_ctx, test_cb, m_ctx[ctx_name], + append_str(m_ctx[ctx_name])) + endfunction + + function bit ctx_queue_match(string ctx_name, string q[$]); + cb_ctx ctx = m_ctx[ctx_name]; + if (ctx.m_strq.size() != q.size()) return 0; + foreach (ctx.m_strq[i]) begin + if (ctx.m_strq[i] != q[i]) return 0; + end + return 1; + endfunction + + function void ctx_clear(string ctx_name); + m_ctx[ctx_name].m_strq.delete(); + endfunction +endclass + +`UVMT_TEST_BEGIN(callback_test, uvm_callback_testsuite); + string q_expect[$]; + test_cb callback_1, callback_2; + + callback_1 = new("callback_1"); + callback_2 = new("callback_2"); + + ctx.add_callback("foo", callback_1); + ctx.do_callbacks("foo"); + ctx.do_callbacks("bar"); + //$display("%p", ctx.m_ctx["foo"].m_strq); + + q_expect = '{"callback_1"}; + if (!ctx.ctx_queue_match("foo", q_expect)) `UVMT_FAIL(ctx, "add"); + q_expect = '{}; + if (!ctx.ctx_queue_match("bar", q_expect)) `UVMT_FAIL(ctx, "add"); + + ctx.add_callback("foo", callback_2); + ctx.add_callback("bar", callback_2); + ctx.do_callbacks("foo"); + ctx.do_callbacks("bar"); + + q_expect = '{"callback_1", "callback_1", "callback_2"}; + if (!ctx.ctx_queue_match("foo", q_expect)) `UVMT_FAIL(ctx, "add"); + q_expect = '{"callback_2"}; + if (!ctx.ctx_queue_match("bar", q_expect)) `UVMT_FAIL(ctx, "add"); + + `UVMT_DONE(ctx, "add"); +`UVMT_TEST_END + +`UVMT_TEST_BEGIN(delete_test, uvm_callback_testsuite); + string q_expect[$]; + test_cb callback_1, callback_2; + + callback_1 = new("callback_1"); + callback_2 = new("callback_2"); + + ctx.add_callback("foo", callback_1); + ctx.add_callback("foo", callback_2); + ctx.do_callbacks("foo"); + q_expect = '{"callback_1", "callback_2"}; + if (!ctx.ctx_queue_match("foo", q_expect)) `UVMT_FAIL(ctx, "add"); + + ctx.delete_callback("foo", callback_1); + ctx.do_callbacks("foo"); + q_expect = '{"callback_1", "callback_2", "callback_2"}; + if (!ctx.ctx_queue_match("foo", q_expect)) `UVMT_FAIL(ctx, "delete"); + + ctx.delete_callback("foo", callback_2); + ctx.do_callbacks("foo"); + q_expect = '{"callback_1", "callback_2", "callback_2"}; + if (!ctx.ctx_queue_match("foo", q_expect)) `UVMT_FAIL(ctx, "delete"); + + `UVMT_DONE(ctx, "delete"); +`UVMT_TEST_END + +function uvm_callback_testsuite::new(); + super.new("uvm_callback"); + + add_feature("add"); `UVMT_REGISTER_TEST(callback_test); + add_feature("delete"); `UVMT_REGISTER_TEST(delete_test); + add_feature("add_by_name", uvmt::S_DISABLED); + add_feature("delete_by_name", uvmt::S_DISABLED); +endfunction + +`UVMT_TOP(uvm_callback_testsuite) diff --git a/test_regress/t/t_uvm_queue.pl b/test_regress/t/t_uvm_queue.pl index b46df68852..ac2cedce0d 100755 --- a/test_regress/t/t_uvm_queue.pl +++ b/test_regress/t/t_uvm_queue.pl @@ -13,8 +13,11 @@ compile( verilator_flags2 => ["--binary", "--timing", "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", - "-Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-CASTCONST -Wno-REALCVT", - "-It/t_uvm", "-DUVM_REGEX_NO_DPI"], + "-Wno-CASEINCOMPLETE -Wno-CASTCONST -Wno-SYMRSVDWORD -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC", + "-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream + "-Wno-ZERODLY", # TODO issue #4494, add support" + "-Wno-ENCAPSULATED", + "-It/t_uvm", "-DUVM_REGEX_NO_DPI -DUVM_CMDLINE_NO_DPI -DUVM_NO_DPI -DUVM_HDL_NO_DPI"], verilator_make_gmake => 0, make_main => 0, ); diff --git a/test_regress/t/t_uvm_queue.v b/test_regress/t/t_uvm_queue.v index 8ac3b4794f..e0f19fc7b8 100644 --- a/test_regress/t/t_uvm_queue.v +++ b/test_regress/t/t_uvm_queue.v @@ -5,10 +5,10 @@ // SPDX-License-Identifier: CC0-1.0 `include "uvmt_unit.svh" -`include "uvmt_logs.svh" +`include "uvm_pkg.sv" +`include "uvmt_extras.svh" -`include "base/uvm_object.svh" -`include "base/uvm_queue.svh" +import uvm_pkg::*; typedef uvm_queue #(string) strq_t; typedef uvm_queue #(int) intq_t; @@ -20,8 +20,8 @@ class uvm_queue_testsuite extends uvmt::uvm_testsuite; extern function new(); virtual task setup(); - strq_t::uvmt_drop_globals(); - intq_t::uvmt_drop_globals(); + uvmt_queue#(string)::drop_globals(); + uvmt_queue#(int)::drop_globals(); m_strq = new("strq"); m_intq = new("intq"); @@ -99,10 +99,7 @@ class insert_get_test extends uvmt::uvm_test #(uvm_queue_testsuite, "insert_get_ ctx.m_strq.insert(5, "sixth"); ctx.m_strq.insert(0, "first"); //if (ctx.m_strq.size() != 13) begin - if (ctx.m_strq.size() != 12) begin - $display("queue size: %0d", ctx.m_strq.size()); - `UVMT_FAIL(ctx, "insert"); - end + if (ctx.m_strq.size() != 12) `UVMT_FAIL(ctx, "insert"); if (ctx.m_strq.get(0) != "first") `UVMT_FAIL(ctx, "get"); //if (ctx.m_strq.get(12) != "last") `UVMT_FAIL(ctx, "get"); if (ctx.m_strq.get(6) != "sixth") `UVMT_FAIL(ctx, "get");