Verilog · Chapter 7.3 · Compiler Directives
`timescale in Verilog — Simulator Time Unit and Precision
The timescale directive declares the unit and precision of simulation time for every module that follows it. It is the contract that turns a numeric delay of five into a real duration, which might mean five nanoseconds in one project and five microseconds in another. Without a timescale the simulator behaves in a way defined by the tool and quietly varies between vendors. With one, every delay, every time print, and every setup and hold check has a well-defined meaning. The directive looks trivial, since a full line is only half a line of code, but it carries several subtleties that every working engineer hits. This lesson covers the legal unit set, the rounding rule, what happens when modules declare different timescales, how precision sets the global simulator step, and how to choose the right values for different kinds of design.
Foundation16 min readVerilogtimescaleSimulationPreprocessor
Chapter 7 · Section 7.3 · Compiler Directives
1. The Engineering Problem
Two engineers on the same project write testbenches for the same DUT. Engineer A writes:
module tb_a;
reg clk;
initial begin
clk = 0;
forever #5 clk = ~clk;
end
endmoduleEngineer B writes essentially the same thing in a different file. Both run in the same simulation. Engineer A's clock toggles at 100 MHz (every 5 ns); Engineer B's clock toggles at 100 kHz (every 5 µs). The simulation reports $time values that don't agree between the two modules. Setup/hold checks flag spurious violations. Coverage closure drifts.
The root cause: neither file specified a timescale. Without `timescale, the simulator falls back to a tool default — and the two files happened to import headers that set the default differently. The bug is not in the design; it is in the measurement contract.
The fix is one line per file:
`timescale 1ns / 1ps
module tb_a;
reg clk;
initial begin
clk = 0;
forever #5 clk = ~clk; // 5 × 1ns = 5ns → 100 MHz
end
endmoduleAfter the directive, every #N in this file means N × 1 ns and every time check resolves to 1 ps. The simulator's interpretation is no longer ambient state — it is part of the source code. This page is the deep drill on that contract: what the directive declares, what units are legal, how precision rounds, what happens when files disagree, and how to pick the right timescale for ASIC RTL, high-speed interfaces, slow peripherals, and mixed-signal verification.
2. Anatomy of `timescale
The full syntax is one line.
2.1 Syntax — unit and precision
`timescale <time_unit> / <time_precision>
// Examples
`timescale 1ns / 1ps
`timescale 10ps / 1ps
`timescale 1us / 1ns
`timescale 1ps / 100fsThe directive takes two arguments separated by /.
time_unit— the base unit that every numeric delay is multiplied by.#5under`timescale 1ns / 1psbecomes5 × 1ns = 5ns. Under`timescale 1us / 1nsthe same#5becomes5us— a thousand times longer.time_precision— the smallest resolvable time step. Any delay finer than precision is rounded to the nearest precision boundary. Under`timescale 1ns / 1ns, a#5.5becomes#6; under`timescale 1ns / 1ps, the same#5.5is preserved exactly.
The directive applies to every module that follows it in the source file, until either end-of-file or another `timescale overrides it.
2.2 Valid units
The legal set is fixed by IEEE 1364-2005. Each unit is one of the magnitudes 1 / 10 / 100 paired with one of seven SI scales.
1s 10s 100s ← seconds
1ms 10ms 100ms ← milliseconds (10⁻³ s)
1us 10us 100us ← microseconds (10⁻⁶ s)
1ns 10ns 100ns ← nanoseconds (10⁻⁹ s)
1ps 10ps 100ps ← picoseconds (10⁻¹² s)
1fs 10fs 100fs ← femtoseconds (10⁻¹⁵ s)Anything outside this set (e.g., 2ns, 500ps, 1as) is a syntax error. The precision must be ≤ the unit — `timescale 1ns / 1us is illegal because precision (1µs) is coarser than the unit (1ns).
3. Mental Model
4. The Scaling Rule — Numeric Delays Become Wall-Clock Time
Every #N in the source is multiplied by the active time_unit.
// Same source statement: #10 $display(...);
// Three different interpretations depending on timescale.
`timescale 1ns / 1ps // case 1
module fast;
initial #10 $display("Time = %0t", $time);
// Prints at simulated time = 10 × 1ns = 10ns
endmodule
`timescale 1us / 1ns // case 2
module medium;
initial #10 $display("Time = %0t", $time);
// Prints at simulated time = 10 × 1us = 10us
endmodule
`timescale 1ms / 1us // case 3
module slow;
initial #10 $display("Time = %0t", $time);
// Prints at simulated time = 10 × 1ms = 10ms
endmoduleSame #10, three different wall-clock durations — 10 ns, 10 µs, 10 ms. The number is unitless until the timescale supplies the conversion. This is the single most common source of cross-file confusion: a #10 looks identical in every file, but means something different in each.
The same scaling applies to all delay forms — #5, #(PERIOD/2), edge-aligned @(posedge clk) waits (relative to the clock period), $setup / $hold checks, repeat (N) @(posedge clk). Every numeric duration in the source rides on the active timescale.
5. The Precision Rule — Rounding to the Time Step
time_precision is the smallest unit the simulator can represent. Delays finer than precision are rounded to the nearest precision boundary.
`timescale 1ns / 1ns // precision = 1ns
module coarse;
initial begin
#5.5 $display("t = %0t", $time); // Rounds to #6 → t = 6
#3.2 $display("t = %0t", $time); // Rounds to #3 → t = 9
end
endmodule
`timescale 1ns / 1ps // precision = 1ps
module fine;
initial begin
#5.5 $display("t = %0t", $time); // 5.5ns = 5500ps exact → t = 5500
#3.2 $display("t = %0t", $time); // 3.2ns = 3200ps exact → t = 8700
end
endmoduleTwo consequences:
- Sub-precision delays disappear.
`timescale 1ns / 1nswith#0.001rounds to zero — the delay is silently dropped. - Cumulative drift. If every step rounds slightly, hundreds of consecutive delays can accumulate microseconds of error in a long simulation. Critical for timing-sensitive verification (jitter measurements, SerDes equalisation simulations).
The rule of thumb: choose precision fine enough to represent every meaningful delay in the design. For a 100 MHz design with 50 ps jitter tolerance, precision should be at least 10 ps — preferably 1 ps to give margin.
6. Multi-Module Propagation — The Global Precision Rule
When a simulation contains multiple modules with different `timescale directives, two rules apply.
6.1 Each module uses its own unit and precision
`timescale 1us / 1ns
module slow_logger;
initial #10 $display("slow_logger fires at %0t", $time);
// Uses 1us — fires at 10us = 10_000 ns of global time
endmodule
`timescale 1ns / 1ps
module fast_top;
slow_logger u_log();
initial #10 $display("fast_top fires at %0t", $time);
// Uses 1ns — fires at 10ns
endmodulefast_top and slow_logger interpret their own #10 against their own timescales. They co-exist in one simulation but speak different units locally.
6.2 The simulator uses the finest precision globally
Module 1: `timescale 1ns / 1ps
Module 2: `timescale 1ns / 100ps
Module 3: `timescale 1ns / 1ns
Finest precision among the three: 1ps
→ The simulator's internal time step is 1ps.
→ Every module's events are timestamped on the 1ps grid.
→ Module 3's `#5.5` (which it interprets as 5ns + 500ps in 1ns precision)
is now rounded against the 1ns grid before, then placed on the 1ps grid.
Net result: Module 3 still rounds to ns boundaries, but the simulator
internally tracks at 1ps.Two practical implications:
- A single fine-precision module expands the global timeline of every other module. Simulation memory footprint and runtime are proportional to events-per-precision-step, so dropping one module's precision from 1 ns to 1 fs can slow the whole simulation by 1000× without obvious cause.
- The global precision is unobservable at code level — there is no
$timeprecisionprint that says "the simulator is running at 1 ps." Hunt it down via tool-specific flags (+timescale=…,-timescale, vendor reports).
The discipline: standardise the timescale across a project (every file uses the same `timescale 1ns / 1ps) so the global precision is predictable.
7. `resetall — Clearing the Active Timescale
The companion directive `resetall clears all compiler-directive state back to defaults, including the active `timescale.
`timescale 1ns / 1ps
module a; initial #10 $display("ns"); endmodule
`resetall // timescale (and other directives) reset
`timescale 1us / 1ns
module b; initial #10 $display("us"); endmoduleIn practice `resetall is rare — most projects standardise on one timescale and never reset. The directive is mostly seen in IP libraries that want a clean slate after their internal includes.
8. Visual Explanation
Three figures cover the timescale model.
8.1 Visual A — unit and precision
The conceptual picture: `timescale declares two numbers, and they map numeric delays in source to simulated time.
`timescale unit and precision — source-to-time mapping
data flow8.2 Visual B — precision rounding
What happens when a fractional delay doesn't land on a precision boundary.
8.3 Visual C — multi-module precision merge
Same simulation, different timescales — the global step is the finest precision.
9. Choosing the Right Timescale — A Per-Domain Rule
The right timescale depends on the clock frequencies, timing margins, and verification needs of the domain. Four canonical pairings.
| Domain | Recommended | Why |
|---|---|---|
| Digital RTL (ASIC / FPGA) | 1ns / 1ps | Matches sub-GHz clock periods; precision captures setup / hold |
| High-speed interfaces (SerDes, DDR, PCIe) | 1ps / 1fs | Multi-GHz clocks need ps accuracy; jitter measurement needs fs |
| Slow peripherals (UART, I²C, SPI) | 1us / 1ns | µs-scale clocks; fewer time steps → faster simulation |
| Mixed-signal | 1ns / 1ps | Compromise between digital (ns) and analog (ps) domains |
| System-level / RTOS | 1ms / 1us | ms-scale software loops; faster sim for long runs |
Three meta-rules behind the table:
- Pick the unit close to the clock period. A 100 MHz design (10 ns period) wants
1nsunit so delays read naturally (#5for half-cycle); same design at 1 GHz (1 ns period) wants100psor10psunit. - Pick precision fine enough for the tightest timing margin. A 50 ps setup/hold check needs at least
10psprecision; a 1 ps jitter measurement needs100fsprecision. - Pick precision coarse enough to keep simulation fast. Each 100× drop in precision is roughly a 100× drop in simulation throughput for time-dominated benchmarks. Don't go finer than needed.
10. Industry Use Cases
Three patterns where `timescale shows up in production.
10.1 Project-standard header
Most teams standardise on one timescale and put it in a header included by every file:
// VLSI Mentor reference convention
`timescale 1ns / 1psEvery file leads with `include "project_timescale.vh". Cross-file precision is consistent; the global precision is predictable. The 7.1 `include page covers the include mechanism this rides on.
10.2 Datasheet-driven timing parameters
Real timing parameters (setup, hold, propagation, recovery) come from the datasheet in absolute time. A testbench encodes them as parameter real and asserts them against actual events. The timescale is the contract that translates the parameters into events:
`timescale 1ns / 1ps
module timing_check;
parameter real T_SETUP = 2.5; // 2.5 ns — from datasheet
parameter real T_HOLD = 1.5; // 1.5 ns
reg clk, data;
initial begin
@(posedge clk);
#(10 - T_SETUP - 0.5); // 0.5 ns margin
data = 1;
@(posedge clk);
#(T_HOLD + 0.3); // 0.3 ns margin
data = 0;
end
endmoduleThe 2.5 ns figure from the datasheet maps directly to the #(...) expressions because the timescale unit is 1ns. Precision of 1ps gives 1000× more resolution than the timing margin — comfortable headroom.
10.3 Protocol timing modelling
Protocol specs are written in absolute time (I²C: 4.7 µs SCL-low). To model them in a testbench, the timescale needs to be fine enough to express the spec values exactly, coarse enough that simulation doesn't crawl:
`timescale 1ns / 1ps
module i2c_tb;
parameter real T_LOW = 4700; // 4.7 µs in ns
parameter real T_HIGH = 4000; // 4.0 µs in ns
parameter real T_SU_DAT = 250; // 250 ns
// …drive scl / sda using the parameters
endmodule1ns / 1ps works well — protocol values map naturally to nanosecond integers, and 1 ps precision is far below any I²C timing margin.
11. Common Mistakes
Six pitfalls that catch every working engineer at least once.
11.1 No `timescale at all
// No directive — tool-defined default
module loose;
initial #10 $display("Time = %0t", $time);
// Vendor A: 10ns. Vendor B: 10us. Result varies between tools.
endmoduleThe lazy fix is to rely on the tool default; the disciplined fix is to put `timescale 1ns / 1ps (or whatever the project standard is) at the top of every file or include it from a shared header.
11.2 Inconsistent timescales across project files
When File A uses 1us / 1ns and File B uses 1ns / 1ps, the same #10 means 10 µs in A and 10 ns in B. Setup checks fail with mysterious "looks-right-to-me" violations. Standardise via the project-header pattern in §10.1.
11.3 Precision too coarse for the design
`timescale 1ns / 1ns
module example;
initial begin
#5.5 $display(...); // Rounds to 6 — 0.5ns silently lost
#0.001 ...; // Rounds to 0 — delay dropped entirely
end
endmoduleAny time the design has sub-unit timing margins (setup/hold in ps, jitter in ps, analog mixed-signal), bump precision down. The cost is simulation speed; the benefit is correctness.
11.4 Precision too fine for the workload
`timescale 1ns / 1fs
module slow_runner;
// No fs-scale events anywhere — but every event in the project
// is now placed on a 1fs grid. Simulation crawls.
endmoduleThe simulator's global precision is the finest among all modules. One file with 1fs precision silently slows the entire simulation by 1000× compared to a 1ps-only project. Don't go finer than the tightest design margin.
11.5 Using the wrong unit for the domain
UART simulations under 1ps / 1fs waste time on events that don't matter. ASIC RTL under 1ms / 1us can't resolve setup/hold. The §9 table is the working rule: match the unit to the clock period and the precision to the tightest timing margin.
11.6 Forgetting `timescale lifetime is per-file
The directive's scope is from the line it appears on to the next `timescale or end-of-file — not just the next module. If two modules in the same file both need different timescales, write a second `timescale before the second module. In practice, prefer one timescale per file (or per project).
12. Debugging Lab
Three `timescale debug post-mortems
13. Coding Guidelines
Working teams converge on the same six rules.
- Always declare a
`timescale— never rely on tool defaults; they vary between vendors and silently break portability. - One project-wide standard timescale — pick
1ns / 1psfor ASIC,1ps / 1fsfor SerDes,1us / 1nsfor slow-peripheral testbenches; put it in aproject_timescale.vhand`includeit everywhere. - Match the unit to the clock period — a 100 MHz design (10 ns) uses
1nsunit; a 1 GHz design uses100psor10ps; an I²C controller uses1us. - Match precision to the tightest timing margin — setup/hold in ps →
1psprecision; jitter in fs →1fsprecision. - Don't over-specify precision — every 10× drop in precision is roughly a 10× drop in simulation speed; finer than the tightest design margin wastes runtime.
- Document the rationale — leave a one-line comment above the
`timescaledirective explaining why those numbers (// 100MHz clock, 500ps setup margin → 1ns/1ps). Avoids the next engineer changing it without context.
14. Interview Q&A
15. Exercises
Three exercises that turn `timescale into reflex.
Exercise 1 — Predict the simulated time
For each combination, predict the simulated time when $display fires.
| # | Directive | Statement | Predicted $time |
|---|---|---|---|
| 1 | `timescale 1ns / 1ps | #10 $display(...); | ? |
| 2 | `timescale 1us / 1ns | #10 $display(...); | ? |
| 3 | `timescale 1ns / 1ns | #5.5 $display(...); | ? |
| 4 | `timescale 1ns / 1ps | #5.5 $display(...); | ? |
| 5 | `timescale 1ms / 1us | #100 $display(...); | ? |
| 6 | `timescale 1ns / 1ns | #0.4 $display(...); | ? |
Hints. Apply the scaling rule (unit × N) then the precision rule (round to nearest precision boundary).
Exercise 2 — Pick the right timescale
For each scenario, recommend a `timescale directive.
| # | Scenario |
|---|---|
| 1 | A 50 MHz FPGA design with 1 ns setup/hold checks |
| 2 | A DDR4 SerDes lane at 3.2 Gbps with 5 ps jitter measurement |
| 3 | An I²C-master testbench at Standard Mode (100 kHz SCL) |
| 4 | A mixed-signal SAR ADC at 1 MSps with 100 ps clock jitter |
| 5 | An RTOS scheduler simulation with 1 ms tick |
Hints. Match the unit to the clock period and the precision to the tightest timing margin.
Exercise 3 — Debug the precision
In each snippet, identify whether the chosen precision is too coarse, too fine, or appropriate.
// Snippet A
`timescale 1ns / 1ns
parameter real T_SETUP = 0.3; // 300ps setup time
// ...
// Snippet B
`timescale 1ns / 1fs
// Simple 100MHz testbench with no sub-ns timing checks
// ...
// Snippet C
`timescale 1ns / 1ps
parameter real T_SETUP = 0.5; // 500ps setup time
parameter real T_HOLD = 0.2; // 200ps hold time
// ...
// Snippet D
`timescale 1us / 1us
// UART testbench at 9600 baud; bit time ~104us
// ...What to produce. For each, label "too coarse / too fine / appropriate" and justify in one sentence.
16. Summary
`timescale declares two numbers that define the simulator's measurement contract: time_unit (the multiplier that turns numeric delays into wall-clock time) and time_precision (the smallest time-step the simulator can represent). Without it, every numeric delay rides on a tool-defined default and is non-portable.
The scaling rule:
- Every
#Nin source means N × time_unit. - Same
#10is 10 ns under1ns / 1ps, 10 µs under1us / 1ns, 10 ms under1ms / 1us. - The unit applies to every delay form —
#5,#(PERIOD/2),$setup,$hold,repeat (N) @(...).
The precision rule:
- Any delay finer than precision is rounded to the nearest precision boundary.
#5.5under1ns / 1nsrounds to 6; same#5.5under1ns / 1psis exact (5500 ps).- Sub-precision delays round to zero — silent bug source.
The multi-module rule:
- Each module uses its own unit and precision for its own
#N. - The simulator's global event step is the finest precision among all loaded modules.
- One fine-precision IP silently slows the whole simulation.
The per-domain selection rule:
1ns / 1ps— ASIC / FPGA RTL (the industry default).1ps / 1fs— SerDes / DDR / PCIe (multi-GHz clocks, jitter measurement).1us / 1ns— UART / I²C / SPI (slow peripherals, fast simulation).1ns / 1ps— mixed-signal (compromise between digital and analog domains).1ms / 1us— system-level / RTOS (long-running software loops).
The day-to-day discipline:
- Every file leads with
`timescale— or`includea project-standard header that does. - One project-standard timescale. Cross-file consistency makes global precision predictable.
- Match unit to clock period, precision to tightest margin. Don't over-refine — every 10× precision drop costs ~10× simulation speed.
- Document the rationale. One-line comment above the directive — saves the next engineer's debug session.
The next sub-page closes Chapter 7: 7.4 Conditional Compilation covers `ifdef / `ifndef / `elsif / `endif for build-target gating — synthesis vs simulation, fast vs slow models, debug vs release builds.
After Chapter 7 closes, Chapter 8 picks up with system tasks & functions — $display, $monitor, $random, $readmemh — the simulation-infrastructure layer that the timescale ultimately serves.
Related Tutorials
- `define — Chapter 7.2; macro mechanism for sharing the timescale via a project header.
- `include — Chapter 7.1; the file-inclusion mechanism that propagates a project-standard timescale.
- Compiler Directives — Chapter 7; the parent overview of the directive family.
- Number Representation — Chapter 4.4; literal syntax for delay values like
#5.5.