The delay_ps task Solution to Passing Delays

In the last post "System Verilog timescale Across Clases Illustrated", I covered some of the troubles of using the realtime type in System Verilog.  This post is the conclusion on a viable and safe way of inserting delays across classes or files.

I had been researching the problem with the realtime type across classes and files, and came across a post on a forum by Dave Rich from Mentor that suggested the possible solution.  The solution is to use only the real part of the realtime type and normalize it before you send it.  Here is the text from the post by Rich.

In SystemVerilog, you can write (timevar = $time/1ns) or better (timevar $realtime/1ns) and you will get your time back in ns. If you need to use timevar as part of a delay expression, make sure you scale it back, i.e. #(timevar*1ns). 

Dave Rich
from comp.lang.verilog reply to "How to know/read current timescale?"

Below is the example code to implement and test out the idea derived from Rich.

 // `timescale 1ps/1ps
 `timescale 1fs/1fs

 package shared;

 class helper;

     static task delay_ps(real delay);
         real t0, t1;
         t0 = $realtime;
        
         $printtimescale;
         $display("delay_ps(%g)", delay);        
         #(delay*1ps);

         t1 = $realtime;
         if (t0 == t1) $error("%m timescale not precise enough");

     endtask // delay_ps

 endclass // helper   
    
 endpackage // shared

 `timescale 1ps/1ps
 // `timescale 1fs/1fs
    
 module tb ();

     task print_time();
         $display("\n%f is tb time\n", $realtime);
     endtask
    
     initial begin

         $display("\n");
         $printtimescale;
         $display("\n");

         print_time();
         #2ps; $display("delay 2ps"); print_time();
         shared::helper::delay_ps(2); print_time();
         shared::helper::delay_ps(2ps/1ps); print_time();
         shared::helper::delay_ps(0.002ns/1ps); print_time();
         shared::helper::delay_ps(0.000002us/1ps); print_time();
         #2fs; $display("delay 2fs"); print_time();
            
         $finish();
        
     end
    
 endmodule

When the shared::helper::delay_ps task is called we are passing variations of time which are all normalized to be in ps.  As long as you divide by ps (the unit that the delay_ps task will multiply by) it all works out.  If you try to do something below the precision that is possible, the task will tell you it was not successful.

The output of the code above is below.

# Time scale of (tb) is  1ps /  1ps
#
#
#
# 0.000000 is tb time
#
# delay 2ps
#
# 2.000000 is tb time
#
# Time scale of (shared.helper.delay_ps) is 1fs / 1fs
# delay_ps(2)
#
# 4.000000 is tb time
#
# Time scale of (shared.helper.delay_ps) is 1fs / 1fs
# delay_ps(2)
#
# 6.000000 is tb time
#
# Time scale of (shared.helper.delay_ps) is 1fs / 1fs
# delay_ps(2)
#
# 8.000000 is tb time
#
# Time scale of (shared.helper.delay_ps) is 1fs / 1fs
# delay_ps(2)
#
# 10.000000 is tb time
#
# delay 2fs
#
# 10.002000 is tb time