Compensating for different timeunits between SystemVerilog packages

I am performing transaction recording in a custom UVM monitor, where the agent has a different timeunit to the rest of the test bench. When I measure the current simulation time, the $time system call correctly reports the time for the current package using the timeunit of that package. However, when I pass that value to the begin_tr() or end_tr() functions, it treats the values as if they are reported for the global timeunit, which doesn’t necessarily match the timeunit of the package. Is there a simple way to obtain the global timeunit to scale the values in a portable manner?

The intention is to create a reusable agent that will exist in test benches of differing timeunits.

In reply to Paul McKechnie:
Communicating time values across multiple timescale domains has been a gotchain Verilog since day one. There is no physical time data type, so it is best if you use real numbers and $realtime to avoid truncation, and then normalize your real time values using a mutually agreed upon time literal. For example, the expression

$realtime / 1ps

always results in value where 1.0 means 1 picosecond, regardless of the current timeunit. If that expression gets passed to another scope having a different timeunit, you can multiply it again by 1ps

timeunit 1ns
real timestamp;

timestamp = $realtime / 1pa;
call_another_timunit(timestamp);
timeunit 1ps;
function void call_another_timeunit(real ts);
$display("time current timescale",,  ts * 1ps );
endfunction

Lets say we were at time 100 ps when the fist code snippet executes. $realtime returns 0.1 whereas $time would have rounded to return 0. 1ps returns 0.001 when the timeunit is in nanoseconds. So (0.1/0.001) = 100. Whatever the timeunit, this expression would always return 100.

Now call the function call_another_timunit() with the value 100. If we multiply it by 1ps when the timeunit is 1ps, that results in 100 * 1 = 100.

There’s also a uvm_tlm2_time class that could probably help you here. You’d need to have a config field inside your UVC which tells it what the global precision is:


class uvc_config;
  enum { PS, NS } resolution;

  function time get_cur_time();
    uvm_tlm2_time t = new();
    return get_realtime($time(), resolution == PS : 1.0e-12 ? 1.0e-9;
  endfunction
endclass


class some_component;
  task some_task();
    // do stuff
    begin_tr(..., .begin_time(cfg.get_cur_time()));
  endtask
endclass

DISCLAIMER: I haven’t tested the code and it’s sure to have some problems, but you could probably use it as a starting point.

In reply to Tudor Timi:

The reference to t.get_cur_time is missing in the previous code Tudor gave.
Correcting it

class uvc_config;
  enum { PS, NS } resolution;
 
  function time get_cur_time();
    uvm_tlm2_time t = new();
    return t.get_realtime($time(), resolution == PS : 1.0e-12 ? 1.0e-9;
  endfunction
endclass
 
 
class some_component;
  task some_task();
    // do stuff
    begin_tr(..., .begin_time(cfg.get_cur_time()));
  endtask
endclass