Source code for uvm.tlm2.uvm_tlm2_time

#//----------------------------------------------------------------------
#//   Copyright 2010-2011 Synopsys, Inc.
#//   Copyright 2011 Mentor Graphics 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_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 <Why is this necessary>.
#//
from uvm.macros.uvm_message_defines import uvm_error, uvm_fatal
from uvm.base.sv import cat
[docs]class UVMTLMTime(): # # static local real m_resolution = 1.0e-12; // ps by default m_resolution = 1.0e-12 # local real m_res; # local time m_time; // Number of 'm_res' time units, # local string m_name; # # // Function: 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) # //
[docs] @staticmethod def set_time_resolution(res): UVMTLMTime.m_resolution = res
# // Function: 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 <set_time_resolution()>, # // is used. def __init__(self, name="uvm_tlm_time", res=0): self.m_name = name self.m_res = UVMTLMTime.m_resolution if (res == 0) else res self.reset() # // Function: get_name # // Return the name of this instance # //
[docs] def get_name(self): return self.m_name
# // Function: reset # // Reset the value to 0
[docs] def reset(self): self.m_time = 0
# // Scale a timescaled value to 'm_res' units, # // the specified scale def _to_m_res(self, t, scaled, secs): # // ToDo: Check resolution return (t/scaled) * (secs/self.m_res) # // Function: 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)); # //
[docs] def get_realtime(self, scaled, secs = 1.0e-9): return self.m_time*scaled * (self.m_res/secs)
# // Function: 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); # //
[docs] def incr(self, t, scaled, secs = 1.0e-9): if (t < 0.0): uvm_error("UVM/TLM/TIMENEG", cat("Cannot increment uvm_tlm_time variable ", self.m_name, " by a negative value")) return if (scaled == 0): uvm_fatal("UVM/TLM/BADSCALE", "uvm_tlm_time::incr() called with a scaled time literal that is smaller than the current timescale") self.m_time += self._to_m_res(t, scaled, secs)
# // Function: 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); # //
[docs] def decr(self, t, scaled, secs): if (t < 0.0): uvm_error("UVM/TLM/TIMENEG", cat("Cannot decrement uvm_tlm_time variable ", self.m_name, " by a negative value")); return if (scaled == 0): uvm_fatal("UVM/TLM/BADSCALE", "uvm_tlm_time::decr() called with a scaled time literal that is smaller than the current timescale") self.m_time -= self._to_m_res(t, scaled, secs); if (self.m_time < 0.0): uvm_error("UVM/TLM/TOODECR", cat("Cannot decrement uvm_tlm_time variable ", self.m_name, " to a negative value")) self.reset()
# // Function: 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)); # //
[docs] def get_abstime(self, secs): return self.m_time*self.m_res/secs
# // Function: 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)); # //
[docs] def set_abstime(self, t, secs): self.m_time = t*secs/self.m_res
#// Group: 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. # # #