Instance connections
An instance is where one module is used inside another: counter u_counter(.clk, .rst_n, .count(count), .done(done));.
(.clk is shorthand for .clk(clk): it connects the signal of the same name.) A wrong port name, a forgotten input or a signal of the wrong width is legal to type but breaks the design later, and
a simulator reports it only when you compile. The IDE checks each instance against the module it instantiates as you
type, underlines the problem, and offers a fix (⌥Enter / Alt+Enter, the actions popup).
Five inspections (checks the IDE runs as you type; all under Settings | Editor | Inspections | SystemVerilog) do this. Each has its own level in the inspection profile, and a “unit” below means a module, interface, program, primitive or checker:
- Unknown module in an instantiation reports a unit no definition is found for.
- Instance connections reports what a tool would reject against the unit it instantiates: a port or parameter the unit does not have, one given twice, one left out that must be set.
- Unconnected instance inputs reports inputs left out, and a list of connections by position (
sub u(a, b), matched to the ports in order) that leaves out the last ports (an output, for example); both are this one inspection, so turning it off turns off both. - Connection width mismatch reports a port and a signal of different widths.
- Instance connections in macro bodies does the same checks inside a
`definethat creates an instance.
Try it
Section titled “Try it”Open the sample project and wait until indexing has finished (the progress bar at the
bottom right disappears). All steps use the instance u_counter in rtl/top.sv. The sample project’s compile file (.f, the list of source files and defines you give your simulator) is sim.f. Start each step from the original file:
after a step, undo with ⌘Z (macOS) / Ctrl+Z (Windows/Linux) until u_counter reads
counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .done(done)); again. Step 2 needs two undos (the fix, then your deletion). Steps 4, 5 and 7 also change other lines; the file is back to
the original when it matches the sample project’s rtl/top.sv. To start over, close the file without saving or copy
rtl/top.sv from the sample project again.
Errors get a red wavy underline and warnings a yellow one; the message appears when you put the mouse pointer on it.
- In the instance
u_counter, delete.rst_n,(with its comma and space). The instance now lacks an input, so the instance nameu_countergets a wavy underline: a warning (the errors in later steps are red). Put the mouse pointer on it to readInput not connected: 'rst_n'. - Continue from step 1: put the caret (the text cursor) on
u_counter, press ⌥Enter (Alt+Enter) and choose Connect missing ports. The line becomescounter #(.MAX(20)) u_counter(.clk, .count(count), .done(done), .rst_n(rst_n));:.rst_n(rst_n)(the fix writes the long form.port(signal), see Quick fixes) is added at the end, because a signalrst_nis declared intop. Undo to the original. - Change
.count(count)to.cont(count):contis marked as an error,Module 'counter' has no port 'cont'. Undo. - Change
logic [7:0] count;tologic [3:0] count;: the connection.count(count)gets a warning (see Connection widths),Port 'count' is 8 bits wide; 'count' is 4 bits. Undo. - Change
.done(done)to.done(finished), put the caret onu_counterand press ⌥Enter (Alt+Enter), then choose Declare ‘finished’. The linewire finished;appears just above the instance (see Declare missing signals). Undo (twice if needed). - Change
counter #(.MAX(20))tocountr #(.MAX(20)):countris marked as an error,Unknown module 'countr': no module, interface, program, primitive or checker of this name in the project, its libraries or the compile file's libraries. Undo. - On the line that declares
done(just belowlogic [7:0] count;), replace the wordlogicwithcounter_pkg::state_t, so that the line declaresdonewith the typecounter_pkg::state_t.state_tis the enumtypedef enum logic [1:0] {IDLE, COUNT, DONE} state_t;inrtl/counter_pkg.sv, so the signal is 2 bits wide while the portdoneis 1 bit:.done(done)gets a warning,Port 'done' is 1 bit wide; 'done' is 2 bits. (This is what happens when a state variable is wired to a 1-bit flag by mistake.) Undo until the line declaresdoneaslogicagain.
If a step shows nothing, see If it doesn’t work.
What is reported
Section titled “What is reported”Each row’s text is the message you see when you put the mouse pointer on the marked code.
| Reported | Example | Level |
|---|---|---|
| A unit with no definition (Unknown module in an instantiation) | fifi u(...) — Unknown module 'fifi': no module, interface, program, primitive or checker of this name in the project, its libraries or the compile file's libraries |
Error |
| A port the unit does not have | .d(1) — Module 'sub' has no port 'd' |
Error |
| A port connected twice | .clk(a), .clk(b) |
Error |
| More positional connections than ports | sub u(a, b, c, d) for three ports |
Error |
| An interface port left out | u(.c(1'b0)) — Interface port 'bus' is not connected |
Error |
A port .* connects to a signal not declared in the scope (not for a bind, whose names are the target’s, nor in a macro body) |
u(.*) without en — '.*' connects port 'en', but no 'en' is declared here |
Error |
| A parameter the unit does not have, or a local parameter | #(.X(2)), #(.H(2)) — 'H' cannot be overridden: it is a local parameter |
Error |
| A parameter set twice | #(.N(1), .N(2)) |
Error |
| More parameter values than the unit lets you set | #(4, 1, 7) for two |
Error |
| A parameter without a default that is not set | #(.W(4)) when N has no default |
Error |
| Inputs left out (Unconnected instance inputs) | u(.clk(1'b0), .q()) — Input not connected: 'rst' |
Warning |
| A positional list that stops before the last ports, none of them an input (Unconnected instance inputs; see below the table) | sub u(a, b) for module sub(input clk, input rst, output q) — 2 of 3 ports connected by position: 'q' is not connected, on the instance name |
Warning |
A short list of connections by position is reported because, unlike .q(), it does not show whether the last ports
were left open on purpose: if a port is added to the module, every connection after it moves to the next port. To
leave ports open on purpose, write one empty position per port left open (sub u(a, b, );), or connect by name. For sub u(a), which leaves
out rst and q, only Input not connected: 'rst' is shown; q is not listed.
These are not reported: connections left open on purpose (the first bullet), and cases where the IDE cannot be sure what a unit’s ports are (a macro, inactive code, a header that does not parse):
- Outputs left out of a list of connections by name (they stay open), ports listed with an empty connection such as
.rst()or an empty positionu(a, b, ), and ports that.*connects. - An input with a default value (
input logic en = 1'b1), which may be left out. - A parameter without a default that a
defparam u.N = …;in the same file sets. - A list with a macro in it (
u(`PORTS),#(`P)): the macro may expand to any connections, so the list is not counted and no port or parameter is reported missing. - Names and counts, when an item of the unit’s own port or parameter list is a macro or an
`include(module sub(input clk, `EXTRA_PORTS);,#(parameter N = 1, `MORE),#(`include "params.vh")) or sits in an`ifdefbranch the IDE sees as inactive (`ifdef USE_POWER_PINS inout vccd1, `endif): the list may have ports or parameters the IDE cannot see. For a unit without a#(…)list the same holds for a macro or an inactive branch among its body items. A macro inside an item — a width such as[`W-1:0], a type, a default, a procedural block — changes nothing. Known inputs left out of a named list, a port connected or a parameter set twice, and a parameter without a default when no value is given by position are still reported. When only inactive`ifdefbranches (no macro, no`include) may hold more, a port or parameter whose name is written in none of them is reported too (`ifdef SIMULATION , parameter CustomForceName `endifhidesCustomForceName, notNotAParam). - Names and counts, when the unit’s header does not parse (for example a macro used as an operator in a default,
B = A `PLUS 1, or a header still being typed): what it declares is not known. - Instances of units the IDE cannot find, gates and UDPs, and units defined more than once in other files (a definition in the instance’s own file is the one checked against).
A non-ANSI header names the ports an instance connects: module ex(.a(x), .b(y)) has ports a and b, and a
port such as {a, b} has no name, so it can be connected by position only and is not reported when a named list
leaves it out.
Instances a macro creates
Section titled “Instances a macro creates”A `define whose body instantiates a module (OpenTitan’s `PRIM_FLOP_SPARSE_FSM writes every
prim_sparse_fsm_flop) is checked like an instance in code by Instance connections in macro bodies (warning
level): a port or parameter the module does not have, a port connected twice, an input left out and a list of
connections by position that stops early are reported in the body, where you fix them, and at each call of the macro:
| Where | Reported |
|---|---|
In the body, at .q_x |
Module 'flop' has no port 'q_x' |
At a call `SIM_FLOP(u_s, a, b) where SIM is defined |
The instance `SIM_FLOP writes (rtl/macros.svh:3): Module 'flop' has no port 'q_x' |
(the `SIM_FLOP macro and the flop module are shown below.)
The part in parentheses at a call is where the body’s problem is: the file of the `define and the line, in that
file, of the instance the body writes.
In the body, both branches of an `ifdef are checked.
At a call, the warning repeats the body’s problems, but only those in the `ifdef branches this call takes,
with the defines in effect at the call: a `define earlier in the file, and the defines from the compile file and
the settings (see Conditional compilation). For example, with the module in
rtl/flop.sv:
module flop #(parameter int Width = 1) (input logic clk_i, input logic en_i, input logic [Width-1:0] d_i, output logic [Width-1:0] q_o);endmoduleand this macro, starting on line 1 of rtl/macros.svh:
`define SIM_FLOP(__name, __d, __q) \`ifdef SIM \ flop __name (.clk_i(clk_i), .en_i(1'b1), .d_i(__d), .q_x(__q)); \`else \ flop __name (.clk_i(clk_i), .en_i(1'b1), .d_i(__d), .q_o(__q)); \`endifthe body shows Module 'flop' has no port 'q_x' on line 3, in the `ifdef SIM branch. A call
`SIM_FLOP(u_s, a, b) where SIM is not defined shows nothing. Where SIM is defined (a `define SIM before
the call, or SIM in the settings) it shows
The instance `SIM_FLOP writes (rtl/macros.svh:3): Module 'flop' has no port 'q_x'.
In both places, what depends on a call’s arguments is not reported:
- names: a port or parameter whose name is one of the macro’s formal arguments (
__name,__d,__qin`SIM_FLOP; each call decides it); - counts: inputs left out, and connections by position that stop early, when the connection list has an item that may stand
for more connections: another macro (
`CONNS), a pasted name (.``__p``_i), a formal used as a port name (.__port(x)), a formal alone as an item (dff __n (clk, d, __rest)), or`ifdeflines inside the list (which also hide a port connected twice across the branches); the same for parameters, when the parameter list has such an item (#(__w)); - connection widths.
When the macro is defined in several files (a design copied into several trees), a call is checked against the definition its file includes, else the one closest to it in the directory tree.
Connection widths
Section titled “Connection widths”Connection width mismatch warns when a port and the signal connected to it differ in width — legal (the value
is truncated or extended, IEEE 1800 §23.3.3.7) but rarely meant: .d(a) for input logic [7:0] d and
logic [3:0] a reads Port 'd' is 8 bits wide; 'a' is 4 bits. A signal, a select of one (a[3:0], a[i],
a[i +: 4]) and a concatenation of those ({a, b}) are compared, by name or by position.
Widths are compared only where both are constants: ranges of literals, local and package parameters
(localparam int L = 4;, pkg::W), $clog2, and the parameters of the instantiated module as the instance sets them
(#(.W(4)), else their defaults).
A type with a name is read from its typedef:
- an enum is as wide as the type written after
enum:typedef enum logic [4:0] {S0, S1} st_eis 5 bits; with no type written it is anint, 32 bits; - an alias takes the type it names:
typedef logic [7:0] byte_tis 8 bits; - a
struct packedis the sum of its members:struct packed { logic [3:0] a; st_e s; }is 9 bits; aunion packedis as wide as its widest member; - a port typed by a type parameter (
parameter type T = logic, a parameter whose value is a type) takes the type the instance gives it, else the parameter’s default.
For example:
typedef enum logic [4:0] {S0, S1} st_e;module tsub #(parameter type T = logic) (input T d);endmodule
module top; st_e s; logic [7:0] w8; tsub u1(.d(s)); // Port 'd' is 1 bit wide; 's' is 5 bits (T is logic) tsub #(.T(st_e)) u2(.d(s)); // nothing: both are 5 bits tsub #(.T(st_e)) u3(.d(w8)); // Port 'd' is 5 bits wide; 'w8' is 8 bitsendmoduleOnly widths are compared, not kinds of type: an enum port connected to a logic vector of the same width is not
reported.
Nothing is reported when the width would be a guess:
- it depends on a parameter or a type parameter of the module you are in, which that module’s own instances may set
(
parameter Wof the enclosing module); - it depends on a macro, or on a parameter a
defparamin the file sets; - the type is a class, or an unpacked struct or union;
- the type is a struct written right in the declaration (
struct packed {…} x;) or a tagged union (union tagged packed {…}); - the IDE cannot read the type completely: a struct with a member written by a macro, an enum whose base type is
itself a typedef (
typedef enum byte_t {…} e;), or a type it cannot find; - the port’s type is a typedef declared inside the instantiated module over that module’s own parameters
(
typedef logic [W-1:0] w_t;insub), or a type parameter whose default uses a value parameter (parameter type T = logic [W-1:0]): the IDE does not apply the instance’s parameter values there; - the signal is an unpacked array (
logic [7:0] m [4]); a packed array such aslogic [3:0][7:0]is 32 bits and is compared; - the connection is a struct member (
.d(pkt.hdr)) or an expression other than a signal, a select of one or a concatenation; - a parameter’s value does not fit its declared type (
localparam bit [3:0] A = 16;): it is not used to compute a width.
An array of instances (sub u[3:0](.d(bus))) is not compared: each instance takes a slice of the signal. An
interconnect port or net, which has no data type of its own, is not compared either. A signal’s width uses the
parameters visible where the signal is declared (for example the enclosing module’s localparam), not the
instantiated module’s.
Quick fixes
Section titled “Quick fixes”Press ⌥Enter (Alt+Enter) on a problem for its quick fix:
- Connect missing ports (on the instance’s name) adds a named connection for every port left out, after the
existing ones and in their layout: one per line if they are one per line, a comment at the end of the last line
kept on its line. It connects
.rst(rst)where a signal of the same name is visible and fits the port (the same rules as code completion in a port connection), else.rst(). - Remove connection removes a connection the unit has no port or parameter for, or a repeated one, with its comma. Comments around it stay, and a line it leaves blank is removed.
Only the text added or removed changes: the rest of the statement, comments and `ifdef lines included, is left
as written.
Declare missing signals
Section titled “Declare missing signals”On an instance, ⌥Enter (Alt+Enter) offers Declare ‘x’ (or Declare missing signals for several) when
it connects names that are not declared yet. Each gets a declaration with the type of the port it is connected to —
for input logic [W-1:0] d in sub #(.W(4)) u(.d(din)), wire [4-1:0] din;:
- A
logicvector (also an implicit type orreg) is declared a net,wire, as the undeclared name was (an implicit net): any number of drivers stays legal. A name the module assigns in procedural code (x = …,x <= …,x++, a proceduralassign) is declaredlogic, since only a variable can be assigned there;forceandreleasework on nets and change nothing. After`default_nettypewith another kind thanwire(ornone), the action is not offered: the name was a net of that kind. - Another type (
bit,int, a typedef) gives a variable, which may have only one driver: it is declared only when the instance statement is all that uses the name, drives it at most once and connects it to noinout. - The instantiated module’s parameters are replaced by what the instance sets them to, as written (
#(.W(W))gives[W-1:0]), else by their defaults; a type parameter by its type. - A name the module sees through a package it imports is qualified with the package (
p::t), also when the instance’s own scope declares one of the same name. If the port’s type uses a name the module sees at file level in another file, nothing is declared: that file’s declarations may not be visible here. - Unpacked dimensions follow the name. A name connected to several ports is declared once, with the type of the
first; every instance of the statement counts, and an implicit
.dconnectsd. - The declarations go before the first statement that uses one of the names (else that use would declare an
implicit net), and before an attribute such as
(* keep *)that belongs to it; if the instance shares its line with code before it, it moves to a line of its own. If that would put them above a declaration they use, the action is not offered.
Only plain names are declared: expressions, constants and selects are left alone, as are names connected to an
interface port, an interconnect or a non-ANSI port that is part of a signal (.e(f[3:0])), a name that already
names a type, and a name that an array of instances (sub u[1:0](…)) connects anywhere in the scope, because each element takes
a slice. A generate … endgenerate region is not a scope: uses around it count. It is not offered for an instance
that is the body of an if, for or case generate without begin: a declaration there would change what the
construct contains. In a generate block, a name the enclosing module also uses is not declared: declared in the block
it would be another signal.
A definition is looked for where a simulator finds it: in the project and its libraries (modules, interfaces,
programs, primitives and checkers) and in the compile file’s libraries — a file named after the unit in a library
directory (-y, such as fifo.v, with an extension of +libext+ or a usual one), and the units defined in its
library files (-v, whatever their text encoding) and in the headers its sources include from outside the project. A
vendor cell (a Xilinx BUFG, a standard cell) is found once its library is in the compile file, however large the
library. A library file changed on disk is read again when the IDE next refreshes it; the tools for coding agents
refresh every file the compile file and its libraries read before they answer. Without a compile file, the message
says so. A unit named by a macro call (`PFX(fifo) u(...)) and code in an inactive `ifdef branch are not
checked; config blocks and `uselib are not understood.
If it doesn’t work
Section titled “If it doesn’t work”| You see | Likely cause | What to do |
|---|---|---|
| Nothing is marked after the edit | The project is still indexing, or the inspection is turned off | Wait for the progress bar at the bottom right; open Settings (⌘, on macOS, Ctrl+Alt+S on Windows/Linux), Editor | Inspections | SystemVerilog, and check the inspection for that step: step 1 Unconnected instance inputs, step 3 Instance connections, steps 4 and 7 Connection width mismatch, step 6 Unknown module in an instantiation. Step 5’s Declare is an intention (an action offered in the Alt+Enter popup, not a check): it is turned on under Editor | Intentions | SystemVerilog |
N of M ports connected by position on an output you mean to leave open |
A list of connections by position that stops early is warned about, since it does not show the choice | Write the empty positions (sub u(a, b, );) or connect by name (.q()) |
| The instance is greyed out | It is inside an inactive `ifdef branch: nothing in it is checked |
See Conditional compilation |
| No Connect missing ports or Declare … entry in the Alt+Enter popup | The caret is not on the instance name, or the case is one of the exceptions listed above | Put the caret on u_counter itself |
A module you know exists is reported Unknown module |
Its file is not in the project, the compile file or its libraries. A compile file (.f) is the list of source files and defines you give your simulator; the sample project’s is sim.f |
Add the file; see defines from a compile file and Known limitations |
| A connection you expect to be reported is not | A macro or an inactive `ifdef branch may hide ports |
See the cases that are not reported under What is reported |
| A width mismatch is not reported | A width depends on a parameter or type parameter of the module you are in, a macro, a class or unpacked struct, a type the IDE cannot find; the signal is an unpacked array (logic [7:0] m [4]); or the connection is a struct member or an expression |
See Connection widths |
With slang installed, slang reports these problems too; the editor shows this page’s report once, with its quick fixes.