Menu

Verilog Timescale and Delays: Controlling Simulation Time

How the timescale directive sets the unit of #delay`, the rules for combining different units across files, and how delays interact with clocked logic.

This page includes runnable editors - edit, run, and see output instantly.

What "Time" Means in Verilog

Verilog doesn't have a built-in notion of seconds. The simulator advances "time units" - arbitrary integer ticks - and your code uses #N to wait N of them. The `timescale directive is what maps those ticks to real time.

`timescale 1ns / 1ps

module test;
    initial begin
        $display("t = %0t", $time);   // 0
        #5;
        $display("t = %0t", $time);   // 5 ns
        #1.5;
        $display("t = %0t", $time);   // 6500 ps (or 6.5 ns)
        $finish;
    end
endmodule

Two parameters:

  • Unit (first number): what #1 means. 1ns says one tick is one nanosecond.
  • Precision (second number): how finely simulation tracks time within that unit. 1ps says fractional delays are rounded to picoseconds.

The precision can't be coarser than the unit (1ps / 1ns is illegal). Common picks:

  • 1ns / 1ps - the de facto standard. Everything in nanoseconds, sub-nanosecond precision for any gate delays.
  • 1ps / 1ps - when modeling extremely fast circuits or when every delay is sub-nanosecond.
  • 1us / 1ns - for slow, embedded-scale simulations (UART byte times, slow protocols).

Where to Put It

`timescale is a compiler directive, not a module-level construct. It goes at the very top of a file, before any module:

`timescale 1ns / 1ps

module foo(...);
    // ...
endmodule

Its scope is "from this point onward in the compilation order, until the next `timescale or end of compilation". That has a subtle implication: a file without an explicit `timescale inherits whatever the previously-compiled file declared, which depends on the order the compiler reads files. Avoid the surprise: put `timescale at the top of every file.

The browser editor on these docs sets a default timescale for you (typically 1ns / 1ps), which is why the examples in earlier docs worked without declaring one. In a real project you'd be explicit.

#delay in Practice

After `timescale 1ns / 1ps:

#5            // wait 5 ns
#100          // wait 100 ns
#1.5          // wait 1.5 ns (precision allows it)
#0.001        // wait 1 ps (just barely above precision)
#0            // zero-delay; useful for ordering events at the same time

Inside an initial or always block, #N blocks the procedural flow for N time units. The simulator pauses this block (other concurrent blocks keep running) and resumes after the delay.

You can prefix an assignment with a delay:

#10 a = 1;        // wait 10 ns, then assign
data <= #2 new_value;   // schedule the non-blocking assignment 2 ns from now

The first form is the testbench staple. The second (delayed non-blocking) is used in gate-level simulation to model propagation delay.

Generating a Clock

The classic pattern:

`timescale 1ns / 1ps

module test;
    reg clk = 0;
    always #5 clk = ~clk;
    // ...
endmodule

With timescale 1ns / 1ps, #5 is 5 ns. The clock toggles every 5 ns, giving a 10 ns period - a 100 MHz clock. To change the frequency, change the delay:

Half-periodPeriodFrequency
#12 ns500 MHz
#2.55 ns200 MHz
#510 ns100 MHz
#1020 ns50 MHz
#2550 ns20 MHz
#50100 ns10 MHz

If you want a fractional half-period (#2.5), your precision needs to support it - 1ps precision handles anything down to 0.001 ns, so any reasonable frequency is fine.

Mixing Timescales Across Files

A real design has many files, and they can declare different timescales. The simulator uses each file's own timescale to interpret the delays in that file. If module_a.v says `timescale 1ns / 1ps and uses #5, that's 5 ns. If module_b.v says `timescale 1us / 1ns and uses #5, that's 5 us.

This is mostly invisible because the simulator presents a global time axis regardless - but it means the same #N in two files can mean wildly different things. The fix: pick one timescale (industry standard is 1ns / 1ps) and put it at the top of every file. Don't mix.

Delays Are Not Synthesizable

Crucial point: #delay only exists for simulation. The synthesis tool reads:

// In synthesizable RTL - WRONG
always @(posedge clk) begin
    out <= #2 in;
end

…and either ignores the #2 (most tools) or rejects the construct (stricter linters). Real hardware's timing is determined by the clock and by gate propagation delay - both invisible to the source code.

The rule: use # only in testbenches. Synthesizable RTL has no # delays. If you find yourself wanting a delay in synthesizable code, you actually want a counter that ticks down on the clock - that's how real hardware "waits".

$time vs $realtime

Two ways to read the current simulation time:

  • $time returns a 64-bit integer in units of the current timescale's unit.
  • $realtime returns a real in units of the current timescale's unit, but with full precision.

For testbench logging, $time is almost always enough. Reach for $realtime only when you need sub-tick precision in print statements.

Practical Tips

  • Always declare `timescale at the top of every file. 1ns / 1ps is the safe default.
  • Use #delay only in testbenches. Treat its absence in synthesizable code as a static rule.
  • Match clock periods to your target frequency. If you're simulating a 50 MHz design, use a 20 ns clock period - mismatched periods can mask timing-sensitive bugs.
  • For cycle-counted stimulus, use @(posedge clk) instead of #. It's robust against changes to the clock period.

What Comes Next

You've now seen every doc in these Verilog tutorials. From the language fundamentals (wire vs reg, modules, operators), through procedural blocks and control flow, into synchronous design and state machines, and finally the testbench tooling that proves it all works. Time to build something - the playground next to these docs is the same simulator we've been using throughout, ready for whatever module you sketch.

Frequently Asked Questions

What does `timescale 1ns / 1ps mean in Verilog?

It tells the simulator: 'one time unit in this file is one nanosecond, and times are tracked with picosecond precision.' After that directive, #5 waits 5 ns, #1.5 waits 1.5 ns (rounded to picoseconds), and $time is reported in nanoseconds. The first number is the unit; the second is the precision.

Do I need `timescale in every Verilog file?

Best practice: yes. The directive's scope ends at the next \timescaleor the end of compilation, so files without one inherit whatever the previously-compiled file declared. That makes timing non-deterministic across builds. Put`timescale 1ns / 1ps` at the top of every source file - it's the most common convention - and you'll never get a surprise.

What does #5 mean in Verilog?

#5 advances simulation time by 5 time units. The unit comes from the active \timescaledirective. With`timescale 1ns / 1ps, #5is 5 nanoseconds. With`timescale 1us / 1ns, #5is 5 microseconds. The number can be fractional -#1.5` works if your precision is finer than the unit.

Is #delay synthesizable in Verilog?

No. #delay only affects simulation - the synthesis tool ignores or rejects it. Real hardware's timing comes from the clock signal and the propagation delay of gates, not from # statements. Use # freely in testbenches; never write it in synthesizable RTL.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED