// //----------------------------------------------------------------------------- // Copyright 2015 Analog Devices, Inc. // Copyright 2007-2018 Cadence Design Systems, Inc. // Copyright 2017 Cisco Systems, Inc. // Copyright 2007-2014 Mentor Graphics Corporation // Copyright 2013-2020 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 -- 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-2020 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-2020 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-2020 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-2020 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-2020 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-2020 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-2020 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-2020 auto 7.2.4.3 function bit is_open(); return m_is_opened; endfunction : is_open // @uvm-ieee 1800.2-2020 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-2020 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-2020 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-2020 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-2020 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-2020 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-2020 auto 7.2.7.2 protected virtual function void do_close(); endfunction : do_close // @uvm-ieee 1800.2-2020 auto 7.2.7.3 protected virtual function void do_free(); endfunction : do_free // @uvm-ieee 1800.2-2020 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