Skip to content

Compiler directives in Verilog

Introduction

Verilog, as a hardware description language (HDL), includes several compiler directives that guide the simulation and synthesis tools on how to interpret and process code. These directives are not part of the actual hardware design but provide meta-information that affects compilation, simulation timing, and code organization.

Compiler directives in Verilog start with a backtick (`) symbol (not to be confused with an apostrophe). They provide instructions to the Verilog compiler and are processed before simulation or synthesis begins.

Common Verilog directives include:

Directive Purpose
`include Include external files
`define Define macros or constants
ifdef /ifndef / else /endif Conditional compilation
`timescale Define simulation time units and precision
`default_nettype Control default net type (e.g., wire, none)
`undef Undefine a previously defined macro

The include Directive

The `include directive in Verilog is similar to the #include directive in C/C++. It allows one file to include the contents of another source file during compilation. This is extremely useful for organizing large projects and sharing common definitions, parameters, or modules.

Syntax

`include "filename.v"
  • The file name must be enclosed in double quotes (" ") or angle brackets (< >).
  • Double quotes indicate the file should be searched relative to the current directory.
  • Angle brackets may be used for global include paths (similar to header files in C).

Example

// file: defines.v
`define DATA_WIDTH 8
`define ADDR_WIDTH 16

// file: top_module.v
`include "defines.v"

module top;
  reg [`DATA_WIDTH-1:0] data;
  reg [`ADDR_WIDTH-1:0] addr;

  initial begin
    data = 8'hFF;
    addr = 16'hA5A5;
    $display("Data = %h, Addr = %h", data, addr);
  end
endmodule

When this code is compiled, the preprocessor replaces `include "defines.v" with the contents of the defines.v file.

Advantages of include

  • Promotes code reuse and modularity.
  • Simplifies project management.
  • Keeps code organized by separating constants, parameters, and macros.

Best Practices

  • Keep all include files in a dedicated include/ directory.
  • Avoid circular inclusion (e.g., file A includes B and B includes A).
  • Use header files only for declarations and definitions, not executable code.

The timescale Directive

The `timescale directive defines the time unit and time precision for simulation. It tells the simulator how to interpret time delays (# delays) in Verilog code.

Syntax

`timescale <time_unit> / <time_precision>
  • time_unit specifies the base unit for time delays.
  • time_precision defines how precisely the simulator rounds time values.

Both are expressed in seconds, typically using convenient units such as 1ns, 10ps, 100fs, etc.

Example

`timescale 1ns / 1ps

module test;
  reg clk;

  initial begin
    clk = 0;
    forever #5 clk = ~clk; // 5 ns delay
  end
endmodule

In this example: - #5 means 5 nanoseconds, since the time unit is 1ns. - The simulation can represent time steps as small as 1ps (time precision).

Understanding Time Units and Precision

Let’s take a deeper look at how these parameters work.

Time Unit

Defines the default delay value interpretation. For example:

`timescale 10ns / 1ns
#1  10ns delay
#0.1  1ns delay

Time Precision

Defines the minimum step resolution for simulation rounding. For example:

`timescale 1ns / 10ps
#0.005  Rounded to 0.01ns (10ps)

Interaction Between Multiple Files

If different files in a project have different timescale directives, the simulator will interpret delays according to the local timescale in each file.

Example

// File A
`timescale 1ns / 1ps

// File B
`timescale 1us / 1ns

If a module in File A has a delay of #10, it means 10ns, whereas in File B, #10 means 10μs.

The define and undef Directives

The `define directive allows you to define constants or macros globally across your Verilog project.

Syntax

`define MACRO_NAME value

Example

`define CLOCK_PERIOD 10

module clk_gen(output reg clk);
  initial begin
    clk = 0;
    forever #(`CLOCK_PERIOD/2) clk = ~clk;
  end
endmodule

To remove a macro definition, you can use:

`undef CLOCK_PERIOD

Conditional Compilation: ifdef, ifndef, else, endif

Verilog provides conditional compilation directives to control which parts of the code are compiled.

Syntax

`ifdef MACRO_NAME
   // Code compiled if MACRO_NAME is defined
`else
   // Code compiled if MACRO_NAME is not defined
`endif

Example

`define DEBUG

module alu;
  integer a, b, result;

  initial begin
    a = 5; b = 3;
    result = a + b;
`ifdef DEBUG
    $display("DEBUG: a=%0d, b=%0d, result=%0d", a, b, result);
`endif
  end
endmodule

Here, the $display statement executes only if DEBUG is defined.

The default_nettype Directive

This directive defines the default net type for undeclared signals.

Syntax

`default_nettype <type>

Possible types include: wire, tri, or none.

Example

`default_nettype none

module my_design(input a, b, output y);
  assign y = a & b; // Will cause an error if undeclared
endmodule

Setting default_nettype none helps catch undeclared signal errors, improving code safety.

Resetting to Default

At the end of the file, you can restore the default behavior:

`default_nettype wire

The celldefine and endcelldefine Directives

These directives are used in cell library modeling to mark a group of modules as standard cells for synthesis or simulation.

Example

`celldefine
module and_cell (input a, b, output y);
  assign y = a & b;
endmodule
`endcelldefine

These hints help EDA tools identify cell boundaries in a standard cell library.

The resetall Directive

The `resetall directive resets compiler directives to their default state.
Useful when you want to ensure that no previous file settings affect the current compilation.

Example

`resetall
`timescale 1ns / 1ps
`default_nettype wire

Common Mistakes and Debugging Tips

Issue Description Solution
Missing include path File not found during compilation Use simulator flag +incdir+<path>
Mismatched timescale Timing inconsistencies between modules Keep a consistent timescale across files
Undeclared nets Accidental implicit wires Use `default_nettype none
Overused macros Hard to debug errors Limit macro scope and use parameters instead

Best Practices Summary

  • Maintain consistent timescale across all files.
  • Avoid redefining macros with the same name.
  • Comment all compiler directives for clarity.
  • Use relative paths for portability (include "path/file.v").
  • Apply resetall before new configurations.