Skip to content

How names are resolved

SystemVerilog Studio follows the name lookup rules of IEEE 1800. Knowing them helps when a name resolves somewhere you did not expect.

Starting at the scope the name is in (a block, loop, function or task, class, module, interface, program or package) and moving outwards one scope at a time, the plugin checks, for each scope in turn:

  1. the names declared in that scope;
  2. for a class: the members it inherits through extends, all the way up the chain; for an out-of-block method function c::f(): the members of class c;
  3. the names imported into that scope: explicit imports (import pkg::x;) win over wildcard imports (import pkg::*;). A package also provides the names it re-exports (export other::*;, export other::x;, export *::*;), also through pkg::x. The plugin follows exports without checking that the exporting package itself uses the name, so it may resolve a name a strict tool rejects.

The first scope where the name is found wins. So a name imported into a module with import pkg::*; wins over a declaration of the same name at file level, and a member inherited from a base class wins over a variable of the same name in the package around the class.

If no enclosing scope has the name, the whole project is searched: modules, interfaces, programs, packages, classes and functions declared at file level in any file (including files attached as libraries).

  • pkg::x and c::x look only in the package or class.
  • obj.x looks in the type of obj: its class (and base classes), interface, struct or module instance. This works for chains (env.agt.drv.vif), this.x, super.x, indexed handles (q[i].x), generate blocks (g_lane[0].busy) and clocking blocks (vif.cb.req).
  • .port(...) in an instantiation looks in the instantiated module; #(.P(...)) looks at its parameters.

Following IEEE 1800 §3.13, modules, interfaces and programs share one name space, packages have their own, and everything else is scoped. A module and a signal with the same name do not clash, and neither do a package and a variable.

In bind dut chk u_chk(.clk(clk)); the port expressions (clk) are resolved inside the target module dut, wherever the bind statement is written. The bound instance u_chk becomes part of dut: u_chk.flag resolves inside dut, and u_dut.u_chk.flag resolves through an instance u_dut of dut. Bind files in libraries count too.