Every name you give to something in Verilog, such as a module, a variable, a task or a block, is an identifier. A namespace is the region of code in which an identifier must be unique. Namespaces let the same name be used in different places without conflict: every module can have its own signal called clk or count. Verilog has two global namespaces, which span the whole design, and several local namespaces, which are limited to one module, block or construct.
9 min read | Beginner Level
What You'll Learn
- Which names live in the global definitions and text macro namespaces
- How modules, tasks, functions, named blocks, generate blocks and specify blocks create local namespaces
- Which declaration a name refers to when the same name is used in nested scopes
- Common naming mistakes that cause compile errors or silent surprises
Global Namespace
The definitions namespace holds the names of all modules and primitives (including user-defined primitives) in the design. It is global: once a name is used for a module or primitive, it cannot be used for another module or primitive anywhere else, in any file.
module A;
// Statements
endmodule
// cannot use 'module A' because it is already declared in global namespace
module B;
// Statements
endmodule
The second module has to be called something other than A. Declaring module A twice gives an error, or, with some simulators, a warning and the second definition silently replacing the first.
The text macro namespace is global too. Macro names are always used with a leading backtick, such as `ADDR_WIDTH, so they can never clash with other identifiers. A macro stays defined across all files compiled after it, and a later `define of the same name overrides the earlier one for the rest of the compilation:
// file1.v
`define ADDR_WIDTH 32
// file2.v
`define ADDR_WIDTH 16 // Redefined to 16 when file2.v is compiled after file1.v
Every use of `ADDR_WIDTH after file2.v sees 16, including code in later files that expected 32. Most simulators print a warning when a macro is redefined, and `undef ADDR_WIDTH removes a definition explicitly.
Name Prefixes in Reusable IP
When a chip is built from IP blocks delivered by different teams, two blocks may both contain a module called fifo or a macro called `DATA_WIDTH. Because these names are global, the design will not compile, or one block silently uses the other's macro value. IP teams therefore prefix every module and macro name with the name of the IP, such as uart_fifo and `UART_DATA_WIDTH.
Local Namespace
All other namespaces are local: block, module, generate, port, specify and attribute namespaces. Within one local namespace, a name can only be declared once, regardless of what kind of object it is. For example, a module cannot contain both reg count; and wire count;, or a task and a variable with the same name. The same name can, however, be declared again in a different or nested namespace.
Block Namespace
Named blocks, functions and tasks each create a block namespace. It contains the parameters, named events and variables (reg, integer, time, real and realtime) declared inside it. A name declared in an inner block hides the same name from the enclosing module, task or block.
module example;
reg signal;
task myTask;
reg signal; // This 'signal' is local to myTask
begin : inner
reg signal; // This 'signal' is local to this begin-end block
signal = 1; // Refers to the 'signal' of block 'inner'
end
endtask
endmodule
There are three different variables called signal here. Inside block inner, the name refers to the closest declaration, the one in inner. The others can still be reached with their full hierarchical names: example.signal and example.myTask.signal. The block must have a name, here inner: in Verilog, variables can only be declared in a named begin ... end block.
Quick Check
If the declaration reg signal; were removed from block inner, which variable would signal = 1; assign?
Show Answer
example.myTask.signal. The simulator searches outward from the current block, and the next declaration of signal it finds is the one in the task. Only if the task had no signal either would it use example.signal.
Module Namespace
Each module and primitive creates its own module namespace. It contains everything declared directly in the module: functions, tasks, instances, named generate blocks, parameters, genvars, nets and variables. Two modules can therefore use the same names internally without any conflict.
module A;
reg signal; // 'signal' is local to module A
endmodule
module B;
reg signal; // 'signal' is local to module B
endmodule
Instance names also belong to the module namespace of the module that contains them, so A u0(); and B u0(); in the same module conflict, while each of two different modules can have its own instance called u0. The ports of a module form a separate port namespace, which connects the module's interface to the declarations inside it.
Synthesis result: Namespaces do not create any hardware. Synthesis keeps the hierarchy of names, and the synthesized netlist often uses hierarchical names such as u_core/u_alu/sum_reg for its cells, which is how engineers find the logic that came from a particular line of RTL.
Generate Namespace
A generate block creates a generate namespace. Instances, nets, variables and local parameters declared inside a named generate block belong to that block. In a generate loop, every iteration creates a separate copy of the block, each with its own namespace.
// Each iteration creates a block adder_instance[i] with its own
// namespace, so every copy can contain an instance called HA
genvar i;
generate
for (i = 0; i < N; i = i + 1) begin : adder_instance
half_adder HA (
.a(A[i]),
.b(B[i]),
.sum(SUM[i]),
.carry(CARRY[i])
);
end
endgenerate
The loop creates the blocks adder_instance[0], adder_instance[1] and so on, and each contains an instance called HA. The full names, such as adder_instance[2].HA, are all different, so there is no conflict. The genvar i itself is declared in the module namespace; inside each generated block, i behaves like a local parameter with that iteration's value.
Quick Check
Why is the label adder_instance important in the generate loop above?
Show Answer
The label names the generate blocks, so each copy gets a predictable hierarchical name, such as adder_instance[2].HA. Without a label, the simulator assigns its own generated names, which are hard to use in waveforms, testbench references and synthesis reports.
Specify Namespace
A specify block creates a specify namespace. A specparam declared inside it is visible only within that specify block.
specify
specparam Thold = 5; // Thold is visible only inside this specify block
$hold(posedge clk, d, Thold);
endspecify
The attribute namespace is the last local namespace. It holds the names used inside attribute instances, written as (* name = value *), so that attribute names never clash with signal names.
Hierarchical Names in Debugging
Because every module, block and generate copy has its own namespace, every signal in a simulation has a unique hierarchical name, such as tb.u_dut.u_fifo.wr_ptr. Waveform viewers, $dumpvars scopes, %m in messages and testbench probes all use these names. Clear names for instances, named blocks and generate labels make large designs much easier to navigate.
Common Beginner Mistakes
Mistake #1: Two modules with the same name in a project
Wrong: Two files, each containing a different module counter
Right: Give every module a unique name, for example with a prefix for the block it belongs to
Why? Module names live in the global definitions namespace. Depending on the simulator, a duplicate is an error, or the module compiled last silently replaces the other one, so part of the design uses the wrong code.
Mistake #2: Declaring the same name twice in one module
Wrong: reg valid; and later wire valid; in the same module
Right: Use one declaration, and a different name for a different signal
Why? A local namespace allows each name only once, whatever kind of object it is. The compiler reports the second declaration as an error.
Mistake #3: Accidentally hiding a module-level signal
Wrong: Declaring reg data; inside a task while the module also has reg data;, and expecting the task to update the module's data
Right: Use a different name inside the task, or no local declaration at all if the task should use the module-level variable
Why? Inside the task, data now refers to the task's own variable. The module's data is never changed, and nothing warns you about it.
Mistake #4: Declaring variables in an unnamed block
Wrong: begin reg tmp; ... end
Right: begin : calc reg tmp; ... end
Why? In Verilog, only a named block creates a block namespace that can hold declarations. SystemVerilog relaxes this rule, so the unnamed version may compile in a SystemVerilog-capable tool but fail with a plain Verilog compiler.
Practice Exercise
Challenge: Find the Conflicts
Which lines of the code below cause a compile error, and why? Which lines are fine even though they reuse a name?
module top; // 1
wire count; // 2
reg count; // 3
task count_up; // 4
integer count; // 5
begin : step // 6
reg [3:0] count; // 7
end
endtask
sub u0 (); // 8
sub u0 (); // 9
endmodule
module sub; // 10
reg count; // 11
endmodule
Hint
Find the namespace each declaration belongs to: the module top, the task count_up, the block step, or the module sub. A name may appear only once per namespace.
Solution
Errors: line 3, because count is already declared as a wire on line 2 in the module namespace of top; and line 9, because the instance name u0 is already used on line 8 in the same module.
Fine: line 5, because the task has its own block namespace; line 7, because the named block step has its own namespace too; and line 11, because module sub has its own module namespace. The task name count_up on line 4 is also fine, because it differs from count.
Summary
In this tutorial, you learned:
- Module and primitive names share the global definitions namespace and must be unique in the whole design
- Text macros form a second global namespace, and a later
`defineoverrides an earlier one - Modules, tasks, functions, named blocks, generate blocks and specify blocks each create a local namespace
- Within one namespace, a name can be declared only once, whatever kind of object it is
- The same name in a nested namespace hides the outer one, which can still be reached with its hierarchical name
- Generate loops create a separate namespace for every iteration, named after the block label