A delay such as #5 has no unit of its own: it could mean 5 nanoseconds or 5 microseconds. Verilog simulation depends on how time is defined, and the `timescale compiler directive sets that definition. It specifies the time unit and the time precision for all the modules that follow it in the source code.

10 min read | Beginner Level

What You'll Learn

  • What the time unit and time precision of `timescale mean
  • How delays are scaled by the time unit and rounded to the time precision
  • How time is printed with %t, $time, $realtime and $timeformat
  • What happens when modules use different timescales, and the common timescale mistakes

Syntax


`timescale <time_unit>/<time_precision>

// Example
`timescale 1ns/1ps
`timescale 10us/100ns
`timescale 10ns/1ns

The two values have different jobs:

  • Time unit: the unit of every delay and time value in the module. With a time unit of 10ns, #2 means 20 ns.
  • Time precision: the smallest step of time the module can resolve. Delays are rounded to this step, so with a precision of 1ns, a delay of 4.9 ns becomes 5 ns.

Each value is written as an integer followed by a unit. The integer must be 1, 10 or 100, and the unit must be one of these:

CharacterUnit
sseconds
msmilliseconds (10-3 s)
usmicroseconds (10-6 s)
nsnanoseconds (10-9 s)
pspicoseconds (10-12 s)
fsfemtoseconds (10-15 s)

The precision must be equal to or smaller than the unit, so `timescale 1ns/1ps is valid, but `timescale 1ps/1ns is an error. Values such as 5ns or 2ps are also not allowed.

Different parts of a design can use different timescales, and Verilog provides a few constructs to work with them:

  • `timescale sets the unit and precision for the modules that follow it
  • $printtimescale prints the timescale of a module
  • $time and $realtime return the current simulation time, and $timeformat controls how %t prints it

Synthesis result: None. Synthesis tools ignore `timescale together with all # delays, because hardware timing comes from the target library and the layout. The directive only matters for simulation, but there it matters a lot: the same code can give different results with a different timescale.

Example #1: 1ns/1ns

The testbench below drives a signal val and prints a message after delays of 1, 0.49, 0.50 and 0.51 time units, then 5 more. The same testbench is reused with three different timescales in this article. With `timescale 1ns/1ns, the unit and the precision are both 1 ns.


// Declare the timescale where time_unit is 1ns
// and time_precision is also 1ns
`timescale 1ns/1ns

module tb;
  // To understand the effect of timescale, let us
  // drive a signal with some values after some delay
  reg val;

  initial begin
    // Initialize the signal to 0 at time 0 units
    val <= 0;

    // Advance by 1 time unit, display a message and toggle val
    #1      $display ("T=%0t At time #1", $realtime);
    val <= 1;

    // Advance by 0.49 time unit and toggle val
    #0.49   $display ("T=%0t At time #0.49", $realtime);
    val <= 0;

    // Advance by 0.50 time unit and toggle val
    #0.50   $display ("T=%0t At time #0.50", $realtime);
    val <= 1;

    // Advance by 0.51 time unit and toggle val
    #0.51   $display ("T=%0t At time #0.51", $realtime);
    val <= 0;

    // Let simulation run for another 5 time units and exit
    #5 $display ("T=%0t End of simulation", $realtime);
  end
endmodule
Output
ncsim> run
T=1 At time #1
T=1 At time #0.49
T=2 At time #0.50
T=3 At time #0.51
T=8 End of simulation
ncsim: *W,RNQUIE: Simulation is complete.

The first delay of 1 time unit advances time to 1 ns. The next delay of 0.49 ns is smaller than the precision of 1 ns, so it is rounded to 0, and the message prints at the same time, T=1. The delays of 0.50 and 0.51 ns are both rounded up to 1 ns, so their messages print at T=2 and T=3. After 5 more time units, the simulation ends at T=8.

Waveform of val with timescale 1ns/1ns: val rises at 2 ns and falls at 3 ns, and the time axis has no divisions smaller than 1 ns

The waveform has no divisions smaller than a nanosecond, because the precision is the same as the unit. Notice that val does not pulse at T=1: because #0.49 was rounded to 0, val <= 1 and val <= 0 both execute in the same time step, and only the last value, 0, is visible.

Two time rulers from 1 to 3 ns. With timescale 1ns/1ns, the requested times 1.49, 1.50 and 2.51 ns are rounded to the nearest 1 ns tick, giving 1, 2 and 3 ns. With timescale 1ns/1ps, the times are kept exactly at 1.490, 1.990 and 2.500 ns

Quick Check

With `timescale 1ns/1ns, how long does #2.5 wait? What about #0.4 followed by another #0.4?

Show Answer

#2.5 waits 3 ns, because 2.5 rounds to 3. Each #0.4 is rounded on its own to 0, so the two together wait 0 ns, not 0.8 ns. Rounding happens for every delay separately, and small errors can add up or disappear.

Example #2: 10ns/1ns

Only the timescale changes in this example. The time unit is now 10 ns, while the precision stays at 1 ns.


// Declare the timescale where time_unit is 10ns
// and time_precision is 1ns
`timescale 10ns/1ns

// NOTE: Testbench is the same as in previous example
module tb;
  // To understand the effect of timescale, let us
  // drive a signal with some values after some delay
  reg val;

  initial begin
    // Initialize the signal to 0 at time 0 units
    val <= 0;

    // Advance by 1 time unit, display a message and toggle val
    #1      $display ("T=%0t At time #1", $realtime);
    val <= 1;

    // Advance by 0.49 time unit and toggle val
    #0.49   $display ("T=%0t At time #0.49", $realtime);
    val <= 0;

    // Advance by 0.50 time unit and toggle val
    #0.50   $display ("T=%0t At time #0.50", $realtime);
    val <= 1;

    // Advance by 0.51 time unit and toggle val
    #0.51   $display ("T=%0t At time #0.51", $realtime);
    val <= 0;

    // Let simulation run for another 5 time units and exit
    #5 $display ("T=%0t End of simulation", $realtime);
  end
endmodule
Output
ncsim> run
T=10 At time #1
T=15 At time #0.49
T=20 At time #0.50
T=25 At time #0.51
T=75 End of simulation
ncsim: *W,RNQUIE: Simulation is complete.

Each delay is first multiplied by the time unit, and the result is then rounded to the precision. %t prints the time in units of the precision, 1 ns here:

DelayScaled by 10nsRounded to 1nsTime after it
#110 ns10 nsT=10
#0.494.9 ns5 nsT=15
#0.505.0 ns5 nsT=20
#0.515.1 ns5 nsT=25
#550 ns50 nsT=75
Waveform of val with timescale 10ns/1ns: val toggles at 10, 15, 20 and 25 ns

The base unit of the waveform is now tens of nanoseconds, with a resolution of 1 ns. The delay of 0.49 no longer disappears, because 4.9 ns is much larger than the precision.

Example #3: 1ns/1ps

The last example uses a time unit of 1 ns with a precision of 1 ps, which is the most common timescale in testbenches.


// Declare the timescale where time_unit is 1ns
// and time_precision is 1ps
`timescale 1ns/1ps

// NOTE: Testbench is the same as in previous example
module tb;
  // To understand the effect of timescale, let us
  // drive a signal with some values after some delay
  reg val;

  initial begin
    // Initialize the signal to 0 at time 0 units
    val <= 0;

    // Advance by 1 time unit, display a message and toggle val
    #1      $display ("T=%0t At time #1", $realtime);
    val <= 1;

    // Advance by 0.49 time unit and toggle val
    #0.49   $display ("T=%0t At time #0.49", $realtime);
    val <= 0;

    // Advance by 0.50 time unit and toggle val
    #0.50   $display ("T=%0t At time #0.50", $realtime);
    val <= 1;

    // Advance by 0.51 time unit and toggle val
    #0.51   $display ("T=%0t At time #0.51", $realtime);
    val <= 0;

    // Let simulation run for another 5 time units and exit
    #5 $display ("T=%0t End of simulation", $realtime);
  end
endmodule
Output
ncsim> run
T=1000 At time #1
T=1490 At time #0.49
T=1990 At time #0.50
T=2500 At time #0.51
T=7500 End of simulation
ncsim: *W,RNQUIE: Simulation is complete.

Every delay is now represented exactly: 1 ns, then 0.49 ns, 0.50 ns and 0.51 ns, adding up to 2.5 ns, and 5 ns more gives 7.5 ns. Because the precision is 1 ps, %t reports times in picoseconds, so T=1490 means 1.49 ns.

Waveform of val with timescale 1ns/1ps: val toggles at 1, 1.49, 1.99 and 2.5 ns

Quick Check

Which timescale would you need to simulate a clock with a period of 6.4 ns, generated with always #3.2 clk = ~clk;, without any error in its period?

Show Answer

A unit of 1ns with a precision of 100ps or finer, such as `timescale 1ns/100ps or `timescale 1ns/1ps. With `timescale 1ns/1ns, each half period of 3.2 ns rounds to 3 ns, and the clock runs with a period of 6 ns instead of 6.4 ns.

Clocks for High-Speed Interfaces

Many interface standards use clock frequencies whose periods are not whole nanoseconds, such as 156.25 MHz (6.4 ns) for high-speed serial links or 133.33 MHz (7.5 ns) for memories. A testbench with a 1 ns precision silently rounds these clocks to the wrong frequency, and the error grows with every cycle compared with the real device. Testbenches for such designs use a precision of 1 ps or finer.

Printing Time: $time, $realtime and $timeformat

Two system functions return the current simulation time, both in the time unit of the module that calls them:

  • $time returns a 64-bit integer, rounded to a whole number of time units.
  • $realtime returns a real number, which keeps the fraction.

The %t format converts a time value from the module's unit and prints it, by default as a number in the smallest precision used anywhere in the design. That is why the examples above print T=1490 and not T=1.49. The difference between the two functions shows up as soon as time is not a whole number of units:


`timescale 1ns/1ps

module tb;
  initial begin
    #1.49;
    $display ("$time=%0d  $realtime=%0f", $time, $realtime);
    $display ("%%t of $time=%0t  %%t of $realtime=%0t", $time, $realtime);
  end
endmodule
$time=1  $realtime=1.490000
%t of $time=1000  %t of $realtime=1490

$time rounds 1.49 ns to 1 time unit, so it loses the fraction, and even %t can only turn that into 1000 ps. Use $realtime whenever the precision is finer than the unit.

$timeformat changes how %t prints time for the whole simulation. It takes four arguments: the unit as a power of ten (-9 for ns, -12 for ps), the number of decimal places, a suffix string, and a minimum field width:


initial begin
  $timeformat(-9, 3, " ns", 10);    // Print in ns, 3 decimal places
  #1.49 $display ("T=%t", $realtime);
end
T=  1.490 ns

Multiple Timescales in One Design

Each module uses the timescale that was in effect when it was compiled, so a testbench, a design and a vendor model can each have their own. The simulator then runs the whole design at the finest precision of all modules, and %t prints in that precision by default.


`timescale 10ns/1ns
module slow;
  initial #1 $display ("slow: T=%0t", $realtime);    // 1 unit = 10 ns
endmodule

`timescale 1ns/1ps
module tb;
  slow u0 ();
  initial #1 $display ("tb:   T=%0t", $realtime);    // 1 unit = 1 ns
endmodule
tb:   T=1000
slow: T=10000

The same #1 means 1 ns in tb and 10 ns in slow. Both are printed in picoseconds, the finest precision in the design, so tb prints first at 1000 ps and slow at 10000 ps. To check which timescale a module ended up with, call $printtimescale, explained in Verilog Timescale Scope.

Third-Party Simulation Models

Memory and I/O simulation models from different vendors often come with their own `timescale, frequently with a precision of 1 ps or 1 fs to model detailed timing. When such a model is added to a testbench written in 1ns/1ns, the whole simulation switches to the finer precision. Results stay correct, but simulation can slow down noticeably, so verification teams choose a common timescale for the project and check every new model against it.

Common Beginner Mistakes

Mistake #1: A precision too coarse for the delays used

Wrong: `timescale 1ns/1ns with always #3.2 clk = ~clk;
Right: `timescale 1ns/1ps, or any precision at least as fine as the smallest fraction in the delays

Why? Delays are rounded to the precision without any warning. In Example #1, #0.49 disappeared completely, and a 3.2 ns half period becomes 3 ns.

Mistake #2: Relying on a timescale from another file

Wrong: Writing `timescale only in the testbench file and not in the design files
Right: Put a `timescale at the top of every file that contains delays, or set a default with a simulator option

Why? `timescale is a compiler directive. It stays in effect for every file compiled after it until another `timescale appears, so a file without its own directive takes whichever timescale happened to be compiled last. Changing the compile order then changes the simulation results, and many simulators stop with an error when some modules have a timescale and others do not.

Mistake #3: Using $time when the precision is finer than the unit

Wrong: $display("%0d", $time); in a 1ns/1ps module at 1.49 ns, expecting 1.49
Right: $display("%0t", $realtime); or $display("%0f", $realtime);

Why? $time returns an integer number of time units, so it prints 1 and the 0.49 ns is lost. $realtime keeps the fraction.

Mistake #4: Invalid timescale values

Wrong: `timescale 5ns/1ns or `timescale 1ps/1ns
Right: `timescale 1ns/1ns or `timescale 1ns/1ps

Why? The number must be 1, 10 or 100, and the precision cannot be larger than the unit. A 5 ns step has to be written as a delay, such as #5 with a 1 ns unit.

Practice Exercise

Challenge: Predict the Times

The testbench from this article is compiled with `timescale 100ps/10ps. Predict the time printed by each $display.

Hint

Multiply each delay by 100 ps, round to a multiple of 10 ps, and add it to the previous time. %t prints in units of the precision, which is 10 ps.

Solution
DelayScaled by 100psRounded to 10psTimePrinted
#1100 ps100 ps100 psT=10
#0.4949 ps50 ps150 psT=15
#0.5050 ps50 ps200 psT=20
#0.5151 ps50 ps250 psT=25
#5500 ps500 ps750 psT=75

The printed numbers are the same as in Example #2, because the ratio between the unit and the precision is 10 in both cases. Only the meaning of each number changes: here T=75 is 750 ps, while in Example #2 it is 75 ns.

Summary

In this tutorial, you learned:

  • `timescale unit/precision sets the meaning of delays and the smallest time step for the modules that follow it
  • The values must be 1, 10 or 100 with a unit from s to fs, and the precision cannot be larger than the unit
  • Every delay is multiplied by the unit and then rounded to the precision, so fractions smaller than the precision can disappear
  • $time returns whole time units and $realtime keeps the fraction; %t prints in the finest precision of the design, and $timeformat changes that
  • Each module keeps its own timescale, and the simulator runs at the finest precision of all of them
  • Put a `timescale in every file with delays, because the directive carries over between files in compile order
  • Synthesis ignores `timescale; it only affects simulation
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5