The previous article explained what the time unit and precision of a `timescale mean. This article answers a different question: which modules a `timescale applies to. Because `timescale is a compiler directive and not part of a module, its scope follows the order in which the compiler reads the source code, and that can give surprising results when a design is spread over many files.

9 min read | Beginner Level

What You'll Learn

  • How to check the timescale of any module with $printtimescale
  • What timescale a module gets when none is declared
  • How a `timescale carries over to later modules and later files
  • Why changing the include or compile order can change a module's timescale, and how to prevent it

The examples in this article use the system task $printtimescale, which prints the time unit and precision of a module:


$printtimescale;                 // Timescale of the current module
$printtimescale(tb.m_alu);       // Timescale of the module of a given instance

Default timescale

If no `timescale has been read before a module, the simulator applies a default timescale. The default is chosen by the simulator, not by the Verilog standard, and is most often 1ns/1ns. The module below has no `timescale at all:


module tb;
  initial begin
    // Print timescale of this module
    $printtimescale(tb);
    // $printtimescale($root);
  end
endmodule
Output
xcelium> run
Time scale of (tb) is  1ns /  1ns
xmsim: *W,RNQUIE: Simulation is complete.

This simulator uses 1ns/1ns as its default. Another simulator, or the same one with a different command-line option, might use something else, which is one reason to always declare the timescale explicitly.

Standard timescale scope

A `timescale applies to every module that follows it in the source code, until another `timescale is found. In the example below, tb and alu come after the first directive, and des comes after the second one:


`timescale 1ns/1ps

module tb;
  des m_des();
  alu m_alu();

  initial begin
    $printtimescale(tb);
    $printtimescale(tb.m_alu);
    $printtimescale(tb.m_des);
  end
endmodule

module alu;

endmodule

`timescale 1ns/10ps

module des;

endmodule
Output
xcelium> run
Time scale of (tb) is  1ns /  1ps
Time scale of (tb.m_alu) is  1ns /  1ps
Time scale of (tb.m_des) is  1ns /  10ps
xmsim: *W,RNQUIE: Simulation is complete.

Note that the timescale belongs to the module definition, not to the place where it is instantiated. tb instantiates des before the second directive appears in the file, but des is defined after it, so it gets 1ns/10ps.

Quick Check

If a third module ctrl were added at the very end of this file, after des, what timescale would it get?

Show Answer

1ns/10ps. The last directive read before ctrl is `timescale 1ns/10ps, and it stays in effect until another `timescale appears.

Scope between Verilog files

A compiler directive does not stop at the end of a file. Other files can be pulled in with `include, which pastes the contents of the included file at that point, as if it had been written there. The directive in effect at that point therefore also applies to the modules in the included file. Here the previous example is split into three files:


// main.v
`timescale 1ns/1ps

module tb;
  des m_des();
  alu m_alu();

  initial begin
    $printtimescale(tb);
    $printtimescale(tb.m_alu);
    $printtimescale(tb.m_des);
  end
endmodule

`include "file_alu.v"
`include "file_des.v"

// file_alu.v
module alu;
endmodule

// file_des.v
`timescale 1ns/10ps

module des;

endmodule
Output
xcelium> run
Time scale of (tb) is  1ns /  1ps
Time scale of (tb.m_alu) is  1ns /  1ps
Time scale of (tb.m_des) is  1ns /  10ps
xmsim: *W,RNQUIE: Simulation is complete.

The results are the same as before. file_alu.v has no directive of its own, so alu takes the 1ns/1ps that is still in effect from main.v. des gets 1ns/10ps from its own file.

The same carry-over happens when files are not included but listed one after another on the simulator's command line or in a file list: the compiler reads them in that order, and a directive at the end of one file is still active at the start of the next.

Swapping files can change timescale

Now the only change is the order of the two `include lines in main.v. The files file_alu.v and file_des.v stay exactly the same:


// main.v
`timescale 1ns/1ps

module tb;
  des m_des();
  alu m_alu();

  initial begin
    $printtimescale(tb);
    $printtimescale(tb.m_alu);
    $printtimescale(tb.m_des);
  end
endmodule

// NOTE! Swapped order of inclusion
`include "file_des.v"
`include "file_alu.v"
Output
xcelium> run
Time scale of (tb) is  1ns /  1ps
Time scale of (tb.m_alu) is  1ns /  10ps
Time scale of (tb.m_des) is  1ns /  10ps
xmsim: *W,RNQUIE: Simulation is complete.

alu has changed to 1ns/10ps, although nothing in file_alu.v was edited. The `timescale 1ns/10ps in file_des.v is now read first and is still in effect when alu is read.

The source code as the compiler reads it for two include orders. Order 1: timescale 1ns/1ps, module tb, module alu from file_alu.v, then timescale 1ns/10ps and module des from file_des.v, so alu gets 1ns/1ps. Order 2: timescale 1ns/1ps, module tb, then timescale 1ns/10ps and module des from file_des.v, then module alu from file_alu.v, so alu now gets 1ns/10ps

The fix is to put a `timescale at the top of every file that contains a module. Then each module gets the same timescale no matter which files are read before it. The drawback is that changing the precision of a whole design means editing every file, so simulators also provide command-line options that set a default timescale for modules without one, or override the timescale of all modules.

SystemVerilog adds the timeunit and timeprecision keywords, which are written inside a module. They apply only to that module and cannot leak into other files, which solves the ordering problem described here.

Synthesis result: None. Synthesis ignores `timescale and all delays, so the scope of a timescale only affects simulation. A wrong timescale never shows up in the netlist, which is why it can go unnoticed until a simulation gives strange timing.

Quick Check

In the swapped order, what single change to file_alu.v would give alu a timescale of 1ns/1ps again, whatever the include order?

Show Answer

Add `timescale 1ns/1ps at the top of file_alu.v, before module alu. A module always takes the last directive read before it, so a directive in its own file always wins.

File Lists in Large Projects

A chip-level testbench is compiled from a file list with hundreds or thousands of files: the design, reusable IP blocks, memory models and testbench components. Files are added and reordered as the project grows. If some files rely on a timescale from earlier files, an unrelated change to the list can silently change their delays. Project coding guidelines therefore usually require a `timescale in every file, and lint tools check for it.

Delivering IP to Other Teams

An IP block is compiled into many different testbenches, in an order its authors do not control. A behavioral model inside it, such as a PLL or analog front-end model with delays of a few picoseconds, would behave differently if it picked up a 1ns/1ns timescale from the customer's files. IP providers put an explicit `timescale in every file they deliver for this reason.

Common Beginner Mistakes

Mistake #1: Declaring the timescale in only one file

Wrong: Putting `timescale 1ns/1ps only in the testbench file and relying on it for all design files
Right: Put a `timescale at the top of every file that contains a module

Why? The design files get whatever directive was read last, so their timescale depends on the compile order. As the swapped-include example shows, moving one line in a file list can change a module's timescale without any warning.

Mistake #2: Assuming the default timescale is the same everywhere

Wrong: Leaving out `timescale because "the simulator uses 1ns/1ns anyway"
Right: Declare the timescale explicitly, or set the default with a documented command-line option in the project's run scripts

Why? The default is chosen by the simulator, not by the language. The same code can run with different timescales on different simulators, and many simulators report an error when some modules have a timescale and others do not.

Mistake #3: Thinking the instantiation decides the timescale

Wrong: Expecting des to use 1ns/1ps because it is instantiated inside tb, which has 1ns/1ps
Right: Check the directive in effect where module des is defined, or call $printtimescale(tb.m_des)

Why? Timescale is a property of the module definition. Every instance of des, anywhere in the hierarchy, uses the timescale that was in effect when des was compiled.

Mistake #4: Using `resetall without restoring the timescale

Wrong:


`timescale 1ns/1ps
`resetall              // Resets all directives, including timescale
module alu;
  ...
endmodule

Right: Place `resetall first, followed by the `timescale

Why? `resetall sets all compiler directives back to their defaults. Placed after the `timescale, it cancels it, and alu falls back to the simulator default. Placed first, it clears any directive left over from earlier files, and the following `timescale then applies cleanly.

Practice Exercise

Challenge: Predict the Timescales

Four files are compiled in the order shown. What timescale does each module get? Then answer the same question for the compile order d.v, a.v, b.v, c.v.


// a.v
`timescale 1ns/1ps
module top; ... endmodule

// b.v
module ctrl; ... endmodule

// c.v
`timescale 10ns/1ns
module fifo; ... endmodule

// d.v
module mem; ... endmodule
Hint

Read the files in compile order as if they were one long file. Each module takes the last `timescale read before it, or the simulator default if there is none yet.

Solution
ModuleOrder a, b, c, dOrder d, a, b, c
top1ns/1ps1ns/1ps
ctrl1ns/1ps (from a.v)1ns/1ps (from a.v)
fifo10ns/1ns10ns/1ns
mem10ns/1ns (from c.v)Simulator default, or an error

In the second order, d.v is read before any `timescale, so mem gets the default timescale, and many simulators stop with an error because other modules do have one. Only ctrl and mem depend on the order, because they are the only modules without a directive in their own file. Adding a `timescale to b.v and d.v makes every result independent of the order.

Summary

In this tutorial, you learned:

  • $printtimescale prints the time unit and precision of the current module or of a given instance
  • A module that comes before any `timescale gets the simulator's default, which is often but not always 1ns/1ns
  • A `timescale applies to every module defined after it, until the next `timescale, across `include files and across files in a compile list
  • The timescale belongs to the module definition, not to where the module is instantiated
  • Changing the include or compile order can change the timescale of a module that has no directive in its own file
  • Putting a `timescale at the top of every file makes the result independent of the order
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5
Cron Job Starts