If you thought that timescale didn’t matter in SystemVerilog – think again!
And truth be told – I thought that timescale was obviated with SystemVerilog’s new features – and I’m having to think again!
So I had thought that we had finally rid ourselves of the `timescale albatross with SystemVerilog.
If you don’t remember the (old) issue here’s a refresher:
`timescale is a compiler directive used to configure the units and precision of a # delay in Verilog. The syntax is something like this:
`timescale 1ns / 10ps
which means that the time unit of a delay is 1ns and the precision is 10ps (or two decimals of precision in nsÂ as x.xx ns).
Since a delay in Verilog doesn’t have units it relies on the timescale to determine how long the delay will last in simulation.
No problem, right?
Here’s the issue: a `timescale directive has file scope and is “sticky” – once a `timescale is found while compiling everything in that file and following files has that timeunit and timeprecision value until the next `timescale is encountered.
And that was the issue – if you didn’t include a `timescale in your file then you relied on compilation order to get your timescale.Â If the compilation order changed or the upstream file changed it’s unit then all of a sudden your delays were wrong.
SystemVerilog solved this problem in two ways:
- delays now have units!Â So I no longer rely on the timescale time unit to determine how long my delay is.Â Instead of #1;Â I now say #1ns.
- introduction of timeunit and timeprecision keywords – these allow the specification of a timescale within the declaration body of a module, interface, or package; no longer do we rely on a `timescale compiler directive.
Unfortunately the problem wasn’t solved…
While delays can be specified for units – effectively obviating the need for a timescale – there’s a (minor) catch.
If a delay is specified that is more precise than a previously declared timescale then it is rounded to match the timescale precision.
`timescale 1ns / 100ps ... #1.75nsÂ // rounded to 1.8ns
But that’s a minor hiccup – compared to this:
The LRM doesn’t explicitly define what happens when the timeunits aren’t aligned. It seems that when a time (or realtime) typed variable is passed from one timescale domain to another the units are CHANGED to the destination timescale.
This is crazy.Â If I define a realtime variable in a package with a timescale and then pass that variable to a function that is *defined* in another package (or file) timescale the time *units* are changed to match the destination timescale!
What does that mean?
It means that if I have 1.75ns in a 1ns/1ps timescale and pass it to a class declared in a 1ms/1us timescale that the time will be changed to 1.75ms.
An example follows – after the break.
Example: (from the code posted here)
package pkg2; timeunit 1us; timeprecision 1ns; class myclass7; function new(); $printtimescale; endfunction: new task dodelay(realtime delay); realtime predelay; realtime postdelay; realtime elapsed; predelay = $realtime; #delay; postdelay = $realtime; elapsed = postdelay - predelay; $display("Delay = %t, Actual Delay = %t, Pre = %t, Post = %t", delay, elapsed, predelay, postdelay); $printtimescale; endtask:dodelay endclass: myclass7 endpackage: pkg2 program main; timeunit 1ns; timeprecision 100ps; import pkg2::*; initial begin:testsequence realtime delay; realtime predelay; realtime postdelay; realtime elapsed; myclass7 mc7; $timeformat(-9, // units_number: -9 is ns 5, // precision_number: number of ints after decimal " ns", // suffix_string: display this suffix after showing realtime value 10 // minimum_field_width: ); $display("Construct and show timescale"); $printtimescale; mc7 = new(); $display("Delay and show timescale"); delay = 2.75ns; predelay = $realtime; #delay; postdelay = $realtime; elapsed = postdelay - predelay; $display("Delay = %t, Actual Delay = %t, Pre = %t, Post = %t", delay, elapsed, predelay, postdelay); mc7.dodelay(2.75ns); $finish; end:testsequence endprogram:main
Construct and show timescale TimeScale of main is 1 ns / 100 ps TimeScale of pkg2 is 1 us / 1 ns Delay and show timescale Delay = 2.75000 ns, Actual Delay = 2.80000 ns, Pre = 0.00000 ns, Post = 2.80000 ns TimeScale of $unit is 1 ms / 100 us Delay = 2750.00000 ns, Actual Delay = 2750.00000 ns, Pre = 16800003.80275 ns, Post = 16802753.80275 ns TimeScale of pkg2 is 1 us / 1 ns
So units only have meaning within the timescale where the delay is defined.Â If you pass that realtime (or time) variable to a scope with different timeunits then you won’t be getting the time you expected. And the fix? Apparently you’ll need to make sure that everything in your design has the same timeunits and precision!Â Or, at a minimum, ensure that anywhere you are passing time/realtime variables that you are passing them between scopes with the same timeunit.
This is something that should be quickly corrected in the LRM and simulators.
If you use a simulator other than VCS – please give the posted example a try. Let me know if this issue is in other simulators as well.
Another issue – classes and timescale:
A task in a class can have delays – but the LRM doesn’t define how delays are handled in a class. It appears that the only way to set the timescale of a class is with the `timescale compiler directive within the file that contains the class. Further, some classes (like the timer classes provided here) the only delays are specified at construction. (The IDV SystemVerilog Timers have only one # delay – the countdown time. This delay is specified, with units, on construction of the timer. This delay needs to be only as precise as the user constructing the timer requires.) Meaning that the timescale shouldn’t be attached to the class – but to the object that is the constructed class.Â In this case it would be preferred that the timescale should be inherited from the constructing parent class / program / module. In the posted example you’ll see that I tried to set the timeunit/timescale of the class at construction with little luck. If you know how to do this – please let me know.
So guess what: `timescale is back!Â And with a vengeance!Â Don’t be lured into thinking your units are being adhered to…