Skip to content

Known limitations

These are known gaps in the current release; read this page when something finds nothing, shows a syntax error or is missing from a list, to check whether it is a known gap before reporting a bug. The list is grouped by feature. Where they apply, navigation usually finds nothing (rather than the wrong declaration) and Rename leaves that code unchanged; the exceptions are noted below: a few gaps are reported as syntax errors, one inspection can report a name wrongly, and a Rename of a method that overrides a library method goes ahead without checking.

  • Conditional compilation (`ifdef, `ifndef, `elsif, `else, `endif) may appear anywhere, including port lists. Only the active branch is code (see Conditional compilation). The IDE knows a macro if it is defined in this file, in a header the file includes, in an earlier file of the active compile file (the .f list of your sources), in the compile file itself (+define+) or in the plugin settings (see Defines from a compile file and the settings). Headers that no source of the compile file includes are not known, and macros from other files take effect when those are saved. Rename does not change names in inactive code. SystemVerilog 2023 condition expressions (`ifdef (A && !B)) are not supported: the condition counts as false, so the branch is inactive.
  • Line directives (`timescale, `default_nettype, `resetall, `celldefine / `endcelldefine, `unconnected_drive, `pragma, `line, `begin_keywords / `end_keywords, `undef, `undefineall) are recognized anywhere and highlighted, but their effect is not modelled, except `default_nettype for the Undeclared names inspection (under `default_nettype none an implicit net is an error).
  • Escaped identifiers (\bus[0] ) are not supported and are reported as syntax errors.
  • The encrypted lines of a `pragma protect data block are not SystemVerilog and are reported as syntax errors.
  • Macros are not expanded in the code itself. Macro names and the names passed to a macro (for example my_driver in `uvm_component_utils(my_driver)) are navigable (see Macros). Names declared by a macro called among a class’s items (type_id, get_type_name) are members of the class (UVM testbenches); names declared by a macro called anywhere else are not. The class follows edits of its file, of the headers it includes and of the files whose definitions it used; a `define added in a file it reaches otherwise (not included, found through the project) is seen when one of those changes. In a very long macro call, an argument more than about 200 tokens after the opening ( is treated as an ordinary name.
  • A macro used as a type or module name with the declared name on the next line (`WORD_T then w;, `MOD_NAME then u_inst (…);) is reported as a syntax error: a macro call that ends its line is read as a statement or item. Keep the name on the same line.
  • SystemVerilog 2009+ keywords (until, strong, weak, soft, global, implies, …) are keywords in .v files too, so Verilog-2005 code using them as names shows syntax errors.
  • `include is followed both ways (see How names are resolved): a scope sees the declarations of the files it includes, and a file included into a package, class or module sees the names where it is included, except for a header included in more than 32 files and continuous assignments in a module-body fragment (below). An include whose file several project files could be (found through +incdir+) offers all of them.
  • A file that a class body or a module body includes (methods, properties and constraints, or assignments, instances, always blocks and assertions at the top of the file, as UVM base sequences and generated testbenches split their code) is read as class or module items and reported only where no file includes it (“Class item outside a class”, “Module item outside a module”). Its declarations are the including class’s or module’s, reached as that scope’s own (in it, through a member access obj.m(), from a subclass). Names in a class-body fragment are looked up in the including class, and names in a module-body fragment’s procedural code (initial for (… Width …)) in the including module; a name in a continuous assignment at the top of a module-body fragment (assign sig = …;) is not resolved. local or protected on a fragment’s methods is not checked.
  • A module or program declared inside a module is read as the next unit: the outer module ends before it, is reported as missing its endmodule, and its final endmodule is reported as a syntax error. Interfaces and classes may be nested.

  • A few SystemVerilog Assertion forms are reported as syntax errors (the rest of the file is not affected): a clocking event as an argument of a sampled-value function ($rose(a, @(posedge clk))), and a sequence method on an instance with arguments (s(b ##1 c).triggered). Sequence and property operators are accepted permissively (a property operator such as |-> is also accepted inside a sequence).

  • A property or sequence without its end keyword ends before the next keyword that starts a module or class item or a data-type keyword that starts a declaration; a declaration of a user-defined type (my_t z;) right after it is taken into the error. A covergroup without endgroup ends only before an item keyword or end keyword (int cp: coverpoint is a legal coverage item), so a variable declaration right after it (logic z;) is taken into the error.

  • A broken property/sequence body is skipped token by token, not bracket-balanced: a type inside brackets ($bits(logic [3:0]), type(int)) ends the skip early, giving a few extra errors.

  • A generate block without its end takes the rest of the module in (legal nesting), up to endmodule.

  • A Verilog-95 (non-ANSI) header without its ; (module m(a, b)) keeps the module’s name, but the port declarations that follow it are reported as syntax errors until the ; is added.

  • Rows of a primitive’s table are checked for their shape (inputs : [state :] output ;, edges in parentheses), not symbol by symbol: 1'b0 : 1; or an empty row ; are not reported.

  • A primitive instance without a name (my_udp (y, a, b);), timing checks in specify blocks ($setup, $hold, …) and edge-sensitive paths ((posedge clk => (q +: d)) = 1;) are reported as syntax errors; the rest of the module and the file keep their place.

  • Declarations at file level outside any module or package (compilation-unit scope) are visible in their own file. From other files, only modules, interfaces, programs, packages, classes and functions are found.

  • An import applies to its whole scope regardless of where the import statement is written.

  • Hierarchical paths that start at a top-level module name (tb.dut.u1.sig) and references into the local variables of functions and tasks are not resolved.

  • Without a compile file, an `include "name" that finds several files of that name equally close (a template directory next to several generated trees) counts as including them only where no other file includes them alone. A header included both ways is looked up in the scope of the file that includes it alone.

  • Checkers and user-defined primitives are not linked by Go to Declaration, Find Usages or Rename: an instantiation my_check u(...) or my_udp u(...) finds nothing, and names inside a primitive are not resolved. Names declared inside a checker (its ports and variables) are found inside the checker and do not clash with the module around it.

The Undeclared names inspection reports nothing it cannot be sure of, so it misses some undeclared names:

  • In a scope whose macros, included files, imported packages or base classes are not all found.
  • Wherever the name is written in inactive code, a macro body or another file’s top-level hidden text.
  • Packages re-exported through a wildcard-imported package (export q::*): their hidden text is not consulted.
  • Escaped identifiers (\cnt) are not supported (a syntax error in your own code, see Preprocessor above), so they never match cnt. (The scan that finds the module names in library files does read an escaped module name such as \cell+x.)

It may also report a name it should not, in one rare case. A macro called only inside an `ifdef branch the IDE sees as inactive (in a scope’s own text, or in a file another file includes; an include guard around the whole file does not count) and defined nowhere in the project, the compile file or the settings is taken for one in a branch that is not compiled (OpenTitan’s `BUS_AW, given on the command line). If a simulator gets that macro some other way and its text declares the name, the name is reported.

A name that only a file generated at build time declares (OpenTitan’s RndCnst*Default) is reported while that file is not in the project.

Unknown members and names through instances

Section titled “Unknown members and names through instances”

A name through an instance (dut.gen_generic.u_impl) is checked against the module of that name in the project. When the build uses another module of the same name that the project does not have (OpenTitan’s prim wrappers, generated at build time, over the prim_generic module the checkout holds; a black-box stub standing for a vendor model), names only the build’s module declares are reported. An implicit net or a label written as an escaped identifier (\w_impl) in the module is reported when reached through an instance.

Find Usages’ Value read / Value write groups and the agent tool sv_drivers read the code as written, without elaborating it (working out the final design with the parameter values applied, as a simulator does). So a driver inside if (WIDTH > 8) in a generate block is listed even when WIDTH is 4, and each instance of a module is followed on its own.

  • In Find Usages, a connection to an instance of a module the IDE does not find (or finds twice), a connection written in a `define body, and a signal passed to a macro call are listed under Value write (they count as both a read and a write). sv_drivers lists them under unknown instead.
  • A .clk connection is a usage of both the port and the signal: Find Usages lists it under Value write.
  • sv_drivers follows the hierarchy one way per chain. Drivers: down into the child from an output connection, up to the parents from an input port. Loads: up from an output port, down from an input connection. To see what drives an input from a sibling instance, ask again at the instance_output place it reports.
  • sv_drivers stops following the hierarchy after about 2,000 places and says so with hierarchy_cut.
  • Bind targets given as an instance path (bind top.u1 chk …) are not supported.
  • Renaming a declaration to the name of an instance added by bind (or the reverse) is not reported as a conflict.
  • After . on a covergroup instance, its built-in methods (sample(), get_coverage(), …) are not offered, and constraint names (h.c_addr.constraint_mode(0)) are not offered.
  • Which keywords are listed first is decided from the code around the caret; where it cannot be told (after a macro call, inside a macro’s arguments), a keyword that fits may be listed with the others at the end.
  • Names are offered whether they are declared before or after the caret.
  • A statement you are still typing, with an open ( or without its ;, can hide the declarations that follow it in the same module until it is complete: names declared below it (for example an instance used before its instantiation line) may be missing from the list.
  • Nothing is offered after $root. or $unit::, after a macro followed by ., and for named arguments of a constructor (new(.).
  • A file included into a package with `include does not see the names of that package, and names declared by a macro called outside a class’s items are not visible; both are offered only if the file uses them elsewhere (as used in this file).
  • A module is offered as an instance (and an instance’s name as u_…) only where an item starts after ;, begin, an end keyword, generate, a generate else, a case-generate item or an `include "…"/`define line (not after a macro call written without ; or an `include <…> line): not as the single item of a generate if (…) or for (…) without begin. A module nested in the module you are in is not offered as an instance.
  • A parameter without a default is taken as set by a defparam only when the defparam is in the same file as the instance; one in another file is not seen, and the instance is reported.
  • The width of what is connected to a port is compared only when both widths are constants the IDE can compute, named types included (enums, typedefs, packed structs and unions, type parameters; see Connection widths). Only widths are compared, not kinds of type: an enum port connected to a logic vector of the same width is not reported. A defparam in another file is not seen, so a port width computed from a parameter it sets may be reported wrongly.
  • Connect missing ports adds connections after the last one, before any `ifdef lines that follow it; a port connected only inside an inactive `ifdef branch is added again.
  • Declare missing signals does not see a name written through a task’s output or ref argument (t(x);, $sscanf(s, "%d", x)): such a name is declared a wire, which may not be written there — change it to logic. It reads `default_nettype only in the instance’s own file: one set in a file compiled before it is not seen.
  • A macro and named connections in the same list (u(`PORTS, .rst(rst))) do not parse yet.
  • In the instance itself, connections and parameter values inside an `ifdef branch the IDE sees as inactive count as absent: set the defines of your build in the compile settings so the right branch is active.
  • An interface port of a non-ANSI header (module m(bus, x); my_if bus; …) is not known to be one, so leaving it out is not reported.
  • Tab does not move between the arguments of a call (the platform needs the parsed argument list, which code being typed usually does not have yet).
  • In a list with more than about 4000 tokens before the caret, nothing is shown.
  • Nothing is shown for the arguments of a covergroup’s new( (its formal arguments), of a let (mx(a, b)), or of a base class or interface class after extends or implements (extends base #(, extends base(, implements ic #().
  • Nothing is shown for a sequence or property instance (s(a, of sequence s(x, y)), or for a later handle of a declaration with several (k a = new("a", 1), b = new().
  • The body of an out-of-block method (function void C::f(); … endfunction) has no Structure View entry of its own (its prototype in the class is listed); with the caret in such a body, Autoscroll from Source selects the enclosing package.
  • Port and argument lists and { … } bodies (constraints, structs, coverpoint bins) do not fold.
  • The closing keyword added on Enter is decided by counting openers and closers in the whole file; code in both branches of `ifdef … `else counts, so an opener repeated in both branches can get an extra closer.
  • A module header with more than eight package imports (module m import a::*; import b::*; …) gets no endmodule on Enter; the indent is still right.
  • New lines are indented with the code style’s indent (spaces unless Use tab character is set), also in files indented with tabs.
  • Run configurations run only (no debugging); a compile file must be on the local disk to be passed to a tool.
  • Tool output locations are recognised only for paths without spaces; in consoles other than the SystemVerilog run configurations, relative paths are resolved against the project directory only.
  • Verilator’s Build and run expects the simulation at obj_dir/Vsim (do not override -o/--Mdir); Icarus writes sim.vvp into the working directory.
  • A relative location that exists both under a run’s working directory and under the project directory gets two links (rare).
  • The run configurations (Run configurations) are tested on macOS and Linux only; Windows is untested, so try it and report problems.
  • Settings of run configurations created with versions before 2.0 are not carried over (the configurations keep their type).
  • The dialog cannot say which of several definitions of a name to prefer; the sv_create_compile_file tool for coding agents can (prefer). See Create a compile file.
  • A bind in a file outside the design (a testbench or formal file binding into it) is not taken; the notification names those files.
  • The new file has no +define+ lines: macros the old compile file defined go into Extra defines by hand.
  • Only .sv, .svh and .v files are searched.
  • sv_insert_instance inserts whole lines before a line you name; it does not insert in the middle of a line, and it does not insert in a comment, a port list, an expression, a statement, or before a generate else.
  • A module cannot be inserted into an interface or a program, nor into itself.
  • A line inside a statement block (for example inside always_comb begin … end) is refused, but the message says units cannot be instantiated “outside a module or interface body, or in a program”, which is misleading there; pass a line between module items instead.
  • A module whose header has a syntax error, or a port with no name ({c, d} in a non-ANSI header), is refused: no instance is guessed.
  • A file with unsaved editor changes is not changed: the dry run shows the editor’s text and apply is refused until you save or discard them.
  • declare_nets declares no net for an interface port, and refuses a port that is only part of a signal (a non-ANSI .e(f[1:0])), a width that depends on a parameter without a default that the call does not set, and an array port whose width depends on {index}.
  • A module name defined in several files needs module_file; two definitions in one file cannot be told apart and are refused.
  • Names from the UVM library resolve only if the UVM sources are in the IDE (inside the project or attached as a library).
  • Without the base class in the IDE, renaming a method that overrides a base-class method (for example a UVM build_phase override) is not checked: the rename goes ahead and the method no longer overrides.
  • slang checks the files on disk: a file with unsaved changes shows no slang problems until it is saved, and slang does not check while you type.
  • There is no official slang build for Linux on ARM and for Intel Macs: build slang 12.0 or newer yourself and set its path in Settings | Languages & Frameworks | SystemVerilog | slang. slang-server has official builds for both.
  • Options of the compile file that only another simulator knows are not passed to slang; give slang’s own options in Extra flags.
  • slang-server 0.3.0 is built on an older slang than slang 12.0: in rare cases the Design Hierarchy and the compiler checks read a construct differently.
  • Without slang-server the Design Hierarchy is static: parameters as written at each instance, generate loops not unrolled, variables not listed. Without slang (the compiler) the static tree is not refreshed by itself: click Refresh after editing.
  • The Design Hierarchy follows the files on disk, not unsaved edits: save, then click Refresh.
  • Windows is untested.