Skip to content

Coding agents (MCP)

SystemVerilog Studio gives coding agents (Claude Code, Codex, Cursor, Junie, …) SystemVerilog tools on the IDE’s own MCP server (MCP, the Model Context Protocol, is the standard way an agent calls tools). Instead of guessing from the text with grep, the agent asks the IDE: where is this declared, what ports does this module have, who instantiates it, what does this macro expand to, is this file correct, and it can rename a declaration or expand verilog-mode AUTOs (special comments such as /*AUTOINST*/ that the editor fills in with port connections; see Expand AUTOs) safely, with a preview first.

The tools need the MCP Server plugin that comes with the IDE (2025.2.2 and newer); where it is disabled, they are not there and the rest of the plugin works as before.

  1. In the IDE, open Settings | Tools | MCP Server (File | Settings on Windows/Linux; on macOS the Settings item of the IDE’s menu) and check Enable MCP Server. The line shows the server’s address, for example http://127.0.0.1:64342/sse.

  2. Connect the agent. Click Auto-Configure next to it (Claude Code, Claude App, VS Code), or add the server yourself: Copy SSE Config (for agents that connect to a URL) or Copy Stdio Config (for agents that start a command) gives the configuration to paste into the agent’s settings. If unsure, use Auto-Configure. For Claude Code, run this in your project’s folder, with the address the settings show:

    Terminal window
    claude mcp add --transport sse jetbrains http://127.0.0.1:64342/sse
  3. Start the agent in the project the IDE has open. In Claude Code, /mcp lists jetbrains as connected, with the sv_ tools among its tools.

Ask in plain words; the agent picks the tool. The examples below are real answers on the sample project.

Agents pick tools better with a few rules about when each one helps (look up an interface before writing an instance, check an edit before writing it, rename instead of search-and-replace). Give your agent these rules once:

  • Claude Code: download SKILL.md and save it as .claude/skills/systemverilog-studio/SKILL.md in your project (or in ~/.claude/skills/ for all projects). Claude Code then uses it when it works on SystemVerilog. Create the folders; if the link opens as text, save the page.
  • Codex, Cursor, Junie and others: paste the contents of AGENTS-systemverilog.md at the end of your project’s AGENTS.md (create it if there is none), or of the file your agent reads instead.

Both hold the same rules. They are optional: the Try it steps work without them.

These steps use the sample project. You type each request to the agent in plain words (for example “Run sv_check on rtl/top.sv”); the agent fills in the tool’s fields. A dry run shows the change as a diff and writes nothing; say “apply it” to write it. After each step that edits a file, undo it in the IDE with Edit | Undo (⌘Z / Ctrl+Z), or copy the file from the sample project again.

  1. Open the sample project and connect your agent to the IDE’s MCP server (see Connect your agent; in Claude Code, /mcp should list jetbrains as connected).
  2. In rtl/top.sv, delete .rst_n, from the instance u_counter yourself in the editor and save (⌘S / Ctrl+S); the tools read the saved file. Ask the agent to run sv_check on rtl/top.sv: it gets a warning at line 8, rule SystemVerilogUnconnectedInputs, Input not connected: 'rst_n', with the fix Connect missing ports. If problems is empty, the file was not saved or the project is still indexing: save, wait for the progress bar at the bottom right, and ask again (or the inspection Unconnected instance inputs is switched off in Settings | Editor | Inspections | SystemVerilog). Then put the line back (Edit | Undo, or retype .rst_n, ) and save, so that rtl/top.sv matches the sample project again; steps 9, 10 and 12 quote its original text.
  3. Ask the agent to run sv_project_info: the compile file (the .f list of source files; see Conditional compilation) is sim.f in the project root, chosen automatically, with the sources rtl/counter.sv, rtl/counter_pkg.sv and rtl/top.sv.
  4. Ask the agent to run sv_find_symbol for counter*: the module counter (rtl/counter.sv, line 1) and the package counter_pkg.
  5. Ask the agent to run sv_module_interface for counter: the parameter MAX (default 10) and the ports clk and rst_n (inputs, 1 bit), count (output, logic [7:0], 8 bits) and done (output, 1 bit).
  6. Ask the agent to run sv_find_references at the name counter in module counter (rtl/counter.sv line 1, column 8): among the uses is the instance at rtl/top.sv line 8.
  7. Ask the agent to run sv_expand_macro at the `LANES in the for (i = 0; …) line of rtl/top.sv (line 11, column 22; the agent can also find it from that text): the expansion is 2, defined at rtl/defines.svh line 5.
  8. Ask the agent to run sv_instances for counter: it is instantiated by top as u_counter (rtl/top.sv, line 8). Then for tb_top: it instantiates the interface my_if as vif_inst.
  9. In rtl/top.sv, replace the port list of u_counter, (.clk, .rst_n, .count(count), .done(done)), with (/*AUTOINST*/) and save. Ask the agent to run sv_expand_autos on rtl/top.sv: the diff adds // Outputs, .count (count[7:0]), .done, // Inputs, .clk and .rst_n, and the file is unchanged. Say “apply it” and the connections are written; undo with Edit | Undo Expand AUTOs, then put the original port list back.
  10. Ask the agent to run sv_rename on rtl/counter.sv with name done and new_name finished: the target is port 'done' in rtl/counter.sv:5. The diff changes the port and assign done in rtl/counter.sv, .done() in the body of the macro COUNTER in rtl/defines.svh, and .done(done) to .finished(done) in rtl/top.sv, with no conflicts; nothing is written. Say “apply it” and the three files are renamed and saved; undo with Edit | Undo; if Undo is greyed out, copy rtl/counter.sv, rtl/defines.svh and rtl/top.sv from the sample project again.
  11. Create the file rtl/cond.sv (right-click rtl in the Project tool window, New | File) with the module cond shown in Parameters and ports in inactive branches and save it (it need not be in sim.f; neither define is set anywhere in the sample project). Ask the agent to run sv_module_interface for cond: parameters has only Width and ports has clk_i and trace_o; inactive_ports has scan_i and scan_o, each with condition `else of `ifndef SYNTHESIS, and inactive_parameters has CustomForceName with condition `ifdef SIMULATION. Delete the file afterwards (right-click it in the Project tool window, Delete).
  12. Ask the agent: “In rtl/top.sv, I want .count(count) changed to .cnt(count) and .done(done) to .done(dnoe); check it with sv_check and content before writing, and do not write it.” It reports Module 'counter' has no port 'cnt' and 'dnoe' is not declared: an implicit net; did you mean 'done'?, and the editor shows rtl/top.sv unchanged. If the agent wrote the file, undo with Edit | Undo and ask again, naming content.
  13. Ask the agent: “Who drives count in rtl/top.sv? Use sv_drivers at line 5, column 15 (logic [7:0] count;).” The drivers are the connection .count(count) of u_counter (rtl/top.sv line 8, kind instance_output), then, inside counter (via u_counter.count), count <= 0; and count <= count + 1; (rtl/counter.sv lines 13 and 17, kind always_ff). loads is empty and loads_total is left out because readers were not asked for (loads is false by default).
  14. Ask the agent: “What reads the port count of counter? Use sv_drivers with loads, at rtl/counter.sv line 4, column 22.” loads lists the port itself (kind port_output: read outside the module), then the connection .count(count) in rtl/top.sv line 8 (kind instance_connection, via u_counter.count), then count <= count + 1; and if (count == MAX - 1) state <= DONE; (rtl/counter.sv lines 17 and 18, kind always_ff). The loads of an output go up to the parent; top itself does not read count, so nothing follows the connection. The answer also has drivers: count <= 0; and count <= count + 1; (lines 13 and 17); and unknown: .count() in the body of the macro COUNTER (rtl/defines.svh line 9, kind macro), a connection whose effect the tool does not decide.
  15. Have the agent build a compile file from the top module and compare it with sim.f. Ask: “Make a compile file for the top module top with sv_create_compile_file, as a dry run, and show me the text.” The answer’s path is top.f, and its text, which starts with // Compile file for top 'top', made by SystemVerilog Studio, has the same +incdir+ line and paths as the hand-written sim.f: +incdir+rtl, rtl/counter_pkg.sv, rtl/counter.sv and rtl/top.sv; only the comment at the top differs (it says what made the file). The package comes first because counter imports it. +incdir+rtl is there because rtl/top.sv includes defines.svh from rtl; an included file is a header, so it is not listed as a source. ambiguous, unresolved, binds_available and notes are empty, and applied is false: no top.f appears in the project. In a project with no .f, saying “apply it” writes the file and makes it the project’s compile file; here keep sim.f. If the agent wrote top.f anyway, delete it (right-click it in the Project tool window, Delete), then in Settings | Languages & Frameworks | SystemVerilog clear Compile file (.f): sim.f is chosen automatically again (see Conditional compilation).

“How is this project compiled?” The agent calls sv_project_info first: the compile file in use, its sources, defines and include directories, and the problems: here the sample’s UVM testbench imports uvm_pkg, which the project does not have.

sv_project_info
{
"compile_file": "sim.f",
"compile_file_chosen": "automatic",
"conditional_compilation": true,
"defines": [],
"extra_defines": [],
"directories": [
"rtl"
],
"sources": [
"rtl/counter.sv",
"rtl/counter_pkg.sv",
"rtl/top.sv"
],
"source_count": 3,
"problems": [
"Package 'uvm_pkg' is imported in 2 files but not found in the project or its libraries: names from it are not resolved",
"'uvm_macros.svh' is included in 1 file but not found in the project or its libraries: its macros and declarations are not seen"
],
"capabilities": {
"semantic_resolution": true,
"macro_expansion": true,
"include_following": "names and defines",
"elaboration": false
},
"toolchain": {
"notes": [
"slang is not installed: set its path in Settings | Languages & Frameworks | SystemVerilog | slang, or download it there (sv_check runs without slang's compile results)",
"slang-server is not installed: set its path in Settings | Languages & Frameworks | SystemVerilog | slang, or download it there (sv_hierarchy needs it)"
]
}
}

“Where is the counter declared?” sv_find_symbol searches the IDE’s index by name or pattern:

sv_find_symbol counter*
{
"symbols": [
{
"name": "counter",
"kind": "module",
"file": "rtl/counter.sv",
"line": 1,
"column": 8
},
{
"name": "counter_pkg",
"kind": "package",
"file": "rtl/counter_pkg.sv",
"line": 1,
"column": 9
}
],
"more": false,
"timed_out": false
}

“What ports does counter have?” sv_module_interface gives the parameters and ports in order, with directions, types and widths in bits (parameters at their defaults), before the agent writes an instance:

sv_module_interface counter
{
"units": [
{
"symbol": {
"name": "counter",
"kind": "module",
"file": "rtl/counter.sv",
"line": 1,
"column": 8
},
"parameters": [
{
"name": "MAX",
"type": "int",
"default": "10",
"local": false
}
],
"ports": [
{
"name": "clk",
"direction": "input",
"type": "logic",
"width": 1
},
{
"name": "rst_n",
"direction": "input",
"type": "logic",
"width": 1
},
{
"name": "count",
"direction": "output",
"type": "logic [7:0]",
"width": 8
},
{
"name": "done",
"direction": "output",
"type": "logic",
"width": 1
}
],
"modports": [],
"arguments": []
}
],
"timed_out": false
}

“Who uses counter?” sv_find_references lists every use of the declaration at a place, as Find Usages does: the instance, the end label, and even the instance a `define writes:

sv_find_references rtl/counter.sv 1:8
{
"declarations": [
{
"name": "counter",
"kind": "module",
"file": "rtl/counter.sv",
"line": 1,
"column": 8
}
],
"usages": [
{
"file": "rtl/counter.sv",
"line": 24,
"column": 13,
"text": "endmodule : counter",
"container": "counter"
},
{
"file": "rtl/defines.svh",
"line": 9,
"column": 3,
"text": "counter __name (.clk(__clk), .rst_n(__rst_n), .count(), .done())"
},
{
"file": "rtl/top.sv",
"line": 8,
"column": 3,
"text": "counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .done(done));",
"container": "top"
}
],
"total": 3,
"more": false,
"timed_out": false
}

“Where is counter instantiated?” sv_instances gives the static hierarchy around a module (instances created by macro calls, generate blocks and bind directives too):

sv_instances counter
{
"units": [
{
"symbol": {
"name": "counter",
"kind": "module",
"file": "rtl/counter.sv",
"line": 1,
"column": 8
},
"instantiated_by": [
{
"parent": "top",
"unit": "counter",
"kind": "module",
"instance": "u_counter",
"file": "rtl/top.sv",
"line": 8,
"column": 23
}
],
"instantiated_by_total": 1,
"instantiated_by_more": false,
"instantiates": [],
"instantiates_more": false,
"instantiates_total": 0
}
],
"timed_out": false
}

“Who drives count, and where does it go?” sv_drivers splits a signal’s uses into drivers (what writes it) and, with loads=true, loads (what reads it), each with its kind: assign, the process (always_ff, always_comb, initial, …), task or function, force, initializer, instance_output (an instance’s output port drives it), instance_input (an input port reads it), port_input (the unit’s own input, driven from outside), port_output (the unit’s own output, read outside), gate, and on the way up instance_connection (a parent’s connection to the port); the full list is in All tools. With depth (default 1) it follows the hierarchy: into the child behind an output connection, and up to the parents that connect an input port (instance_connection); a place reached that way says via which instance and port. Here count in top is driven by u_counter’s output, and inside counter by two lines of its always_ff:

sv_drivers rtl/top.sv 5:15
{
"symbol": {
"name": "count",
"kind": "variable",
"container": "top",
"file": "rtl/top.sv",
"line": 5,
"column": 15
},
"drivers": [
{
"kind": "instance_output",
"file": "rtl/top.sv",
"line": 8,
"column": 54,
"text": "counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .done(done));",
"unit": "top"
},
{
"kind": "always_ff",
"file": "rtl/counter.sv",
"line": 13,
"column": 7,
"text": "count <= 0;",
"unit": "counter",
"via": "u_counter.count"
},
{
"kind": "always_ff",
"file": "rtl/counter.sv",
"line": 17,
"column": 7,
"text": "count <= count + 1;",
"unit": "counter",
"via": "u_counter.count"
}
],
"drivers_total": 3,
"loads": [],
"unknown": [],
"unknown_total": 0,
"more": false,
"timed_out": false
}

“What does square have?” sv_members lists a class’s members with its base classes’ (each with declared_in), their types and qualifiers, a method’s arguments, and which base member a method overrides; for a struct its fields, for an enum its literals. A property typed by a base class’s type parameter (CFG_T cfg) also says what the class binds it to (bound_type), and members a class-level macro declares (type_id) say which call (via_macro):

sv_members square
{
"units": [
{
"symbol": {
"name": "square",
"kind": "class",
"file": "classes/shapes.sv",
"line": 7,
"column": 7
},
"extends": [
{
"written": "shape",
"file": "classes/shapes.sv",
"line": 1
}
],
"members": [
{
"name": "side",
"kind": "property",
"type": "real",
"file": "classes/shapes.sv",
"line": 8,
"column": 8
},
{
"name": "area",
"kind": "function",
"type": "real",
"qualifiers": [
"virtual"
],
"overrides": "shape",
"file": "classes/shapes.sv",
"line": 9,
"column": 25
},
{
"name": "scale",
"kind": "function",
"type": "void",
"arguments": [
{
"name": "factor",
"direction": "input",
"type": "real"
}
],
"file": "classes/shapes.sv",
"line": 12,
"column": 17
}
],
"total": 3,
"more": false,
"complete": true
}
],
"timed_out": false
}

“What is `LANES?” sv_expand_macro expands a macro call as the preprocessor does, with the definition used:

sv_expand_macro rtl/top.sv 11:22
{
"macro": "LANES",
"call": "`LANES",
"expansion": "2",
"truncated": false,
"definition": {
"file": "rtl/defines.svh",
"line": 5,
"text": "`define LANES 2"
},
"timed_out": false
}

“Check top.sv.” After the agent removed .rst_n from the instance u_counter, sv_check reports the input left unconnected, with the quick fix the IDE offers:

sv_check rtl/top.sv
{
"files": [
{
"file": "rtl/top.sv",
"problems": [
{
"line": 8,
"column": 23,
"end_line": 8,
"end_column": 32,
"severity": "WARNING",
"rule": "SystemVerilogUnconnectedInputs",
"message": "Input not connected: 'rst_n'",
"fixes": [
"Connect missing ports"
],
"engine": "svstudio"
}
],
"verdict": "pass",
"slang": "unavailable"
}
],
"more": false,
"timed_out": false,
"slang": {
"state": "unavailable",
"reason": "slang is not installed: set its path in Settings | Languages & Frameworks | SystemVerilog | slang, or download it there"
}
}

A file with no problems is not always a pass. sv_check also says what the file uses that the IDE could not find: the checks that need those names are skipped. On the sample’s UVM package, without the UVM library in the project:

sv_check uvm/my_pkg.sv
{
"files": [
{
"file": "uvm/my_pkg.sv",
"problems": [],
"unresolved": {
"packages": [
"uvm_pkg"
],
"includes": [
"uvm_macros.svh"
],
"macros": [
"uvm_component_utils",
"uvm_fatal"
],
"base_classes": [
"uvm_sequence_item",
"uvm_sequence",
"uvm_driver",
"uvm_agent",
"uvm_env"
]
},
"verdict": "incomplete",
"slang": "unavailable"
}
],
"more": false,
"timed_out": false,
"slang": {
"state": "unavailable",
"reason": "slang is not installed: set its path in Settings | Languages & Frameworks | SystemVerilog | slang, or download it there"
}
}

Add the library (its sources in the project, or +incdir+ and the files in your compile file) and the file is checked in full. sv_check is not a simulator or linter run: use those too.

“Check this edit before you write it.” With content, sv_check checks the text the agent intends to write to one existing file, as if it were saved there, and writes nothing. The file’s `includes, the packages it imports, the compile file’s defines and the other project files are found as usual (a file that another file includes is checked as part of that file). The agent fixes what is reported, then writes. Line and column numbers refer to the proposed text, not to the file on disk. For example, if the agent intends to change the instance in the sample project’s rtl/top.sv to

counter #(.MAX(20)) u_counter(.clk, .rst_n, .cnt(count), .done(dnoe));

sv_check with files ["rtl/top.sv"] and the whole new text of the file as content reports, at line 8, Module 'counter' has no port 'cnt' (column 48) and 'dnoe' is not declared: an implicit net; did you mean 'done'? (column 66), and rtl/top.sv is unchanged.

  • content needs exactly one existing file; for a new file, write it first, then run sv_check on it. Text over the IDE’s analysis limit (idea.max.intellisense.filesize, 2.5 MB by default) is refused.
  • Other files see the file as it is on disk: a declaration the content removes may still resolve elsewhere, and the files that use what the content changes are not checked. After writing, run sv_check on them too.

“Rename the port done of counter to finished.” sv_rename renames a declaration and every use of it, as the IDE’s Rename does. By default it is a dry run: the agent sees the diff, conflicts and notes, and nothing is written:

sv_rename done finished
{
"target": "port 'done' in rtl/counter.sv:5",
"files": [
{
"file": "rtl/counter.sv",
"diff": "--- a/rtl/counter.sv\n+++ b/rtl/counter.sv\n@@ -2,7 +2,7 @@\n input logic clk,\n input logic rst_n,\n output logic [7:0] count,\n- output logic done\n+ output logic finished\n );\n import counter_pkg::*;\n \n@@ -20,5 +20,5 @@\n else if (state == IDLE) state <= COUNT;\n end : seq\n \n- assign done = is_done(state);\n+ assign finished = is_done(state);\n endmodule : counter\n"
},
{
"file": "rtl/defines.svh",
"diff": "--- a/rtl/defines.svh\n+++ b/rtl/defines.svh\n@@ -6,6 +6,6 @@\n \n // a counter made by a macro: Find Usages and Rename see `counter` and its ports here\n `define COUNTER(__name, __clk, __rst_n) \\\n- counter __name (.clk(__clk), .rst_n(__rst_n), .count(), .done())\n+ counter __name (.clk(__clk), .rst_n(__rst_n), .count(), .finished())\n \n `endif\n"
},
{
"file": "rtl/top.sv",
"diff": "--- a/rtl/top.sv\n+++ b/rtl/top.sv\n@@ -5,7 +5,7 @@\n logic [7:0] count;\n logic done;\n \n- counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .done(done));\n+ counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .finished(done));\n \n genvar i;\n for (i = 0; i < `LANES; i++) begin : g_lane\n"
}
],
"places": 4,
"conflicts": [],
"notes": [],
"editor_buffer_differs": [],
"applied": false,
"timed_out": false
}

The diffs, as the agent reads them: the port and its assignment, the connection inside the `COUNTER macro’s body, and the instance in top.sv, where .done(done) becomes .finished(done) so the signal stays connected:

rtl/counter.sv
--- a/rtl/counter.sv
+++ b/rtl/counter.sv
@@ -2,7 +2,7 @@
input logic clk,
input logic rst_n,
output logic [7:0] count,
- output logic done
+ output logic finished
);
import counter_pkg::*;
@@ -20,5 +20,5 @@
else if (state == IDLE) state <= COUNT;
end : seq
- assign done = is_done(state);
+ assign finished = is_done(state);
endmodule : counter
rtl/defines.svh
--- a/rtl/defines.svh
+++ b/rtl/defines.svh
@@ -6,6 +6,6 @@
// a counter made by a macro: Find Usages and Rename see `counter` and its ports here
`define COUNTER(__name, __clk, __rst_n) \
- counter __name (.clk(__clk), .rst_n(__rst_n), .count(), .done())
+ counter __name (.clk(__clk), .rst_n(__rst_n), .count(), .finished())
`endif
rtl/top.sv
--- a/rtl/top.sv
+++ b/rtl/top.sv
@@ -5,7 +5,7 @@
logic [7:0] count;
logic done;
- counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .done(done));
+ counter #(.MAX(20)) u_counter(.clk, .rst_n, .count(count), .finished(done));
genvar i;
for (i = 0; i < `LANES; i++) begin : g_lane

With apply, the rename is made as one undoable command and saved; it is refused when there are conflicts or a file has unsaved changes in the editor.

“Connect u_counter with AUTOINST.” With /*AUTOINST*/ in place of the instance’s connections, sv_expand_autos shows what verilog-mode would write, again as a dry run:

sv_expand_autos rtl/top.sv
{
"files": [
{
"file": "rtl/top.sv",
"changed": true,
"diff": "--- a/rtl/top.sv\n+++ b/rtl/top.sv\n@@ -5,7 +5,13 @@\n logic [7:0] count;\n logic done;\n \n- counter #(.MAX(20)) u_counter(/*AUTOINST*/);\n+ counter #(.MAX(20)) u_counter(/*AUTOINST*/\n+\t\t\t\t// Outputs\n+\t\t\t\t.count\t\t(count[7:0]),\n+\t\t\t\t.done\t\t(done),\n+\t\t\t\t// Inputs\n+\t\t\t\t.clk\t\t(clk),\n+\t\t\t\t.rst_n\t\t(rst_n));\n \n genvar i;\n for (i = 0; i < `LANES; i++) begin : g_lane\n",
"not_supported": [],
"applied": false
}
],
"timed_out": false
}
rtl/top.sv after AUTOINST
--- a/rtl/top.sv
+++ b/rtl/top.sv
@@ -5,7 +5,13 @@
logic [7:0] count;
logic done;
- counter #(.MAX(20)) u_counter(/*AUTOINST*/);
+ counter #(.MAX(20)) u_counter(/*AUTOINST*/
+ // Outputs
+ .count (count[7:0]),
+ .done (done),
+ // Inputs
+ .clk (clk),
+ .rst_n (rst_n));
genvar i;
for (i = 0; i < `LANES; i++) begin : g_lane
Tool What the agent gets
sv_project_info What the IDE compiles with: the compile file (.f) in use and how it was chosen (your setting, or the project’s only one), its define names, include (+incdir+) and library (-y) directories, its source and library files (up to 200, with the total), the extra defines, the problems (reading them; packages imported and files included that the project and its libraries do not have, with how many files use them: Package 'uvm_pkg' is imported in 12 files but not found…), and what the tools can answer (capabilities: names resolve across files and through includes, macro calls expand; elaboration when slang-server is installed and a compile file is chosen, else a toolchain note says what is missing), and the toolchain: the versions of slang and slang-server, or notes saying why one is missing and what it would add (slang’s results in sv_check, sv_hierarchy). It reads the project as it is on disk, after an edit of the compile file too
sv_find_symbol Declarations by name or a pattern with * (uvm_*_agent): modules, interfaces, programs, packages, classes, functions and tasks (a method with its class, pkg::cls, also when its body is written outside the class), checkers, primitives, macros, and package typedefs, parameters, variables and nets — each with its kind, what holds it, and the file, line and column of its name. A class’s properties and a module’s signals are not indexed
sv_module_interface What an instance or a call connects to: a module’s, interface’s or program’s parameters (default as written, whether an instance may set them) and ports in order (direction, type as written, width in bits with every parameter at its default, default value), a checker’s ports (a port without a direction takes the one before it), an interface’s modports, a function’s or task’s arguments (an argument without a direction takes the one before it; const ref included), a class’s parameters, constructor arguments (also of a constructor a class-level macro such as `uvm_object_new declares) and base class (extends, as written), a function’s return type (returns: as written, void, or logic when implicit). A default longer than 200 characters is cut and ends with …. Every definition of the name is in the answer (some only as a summary, see the end of this row); file narrows to one, by the path listed (a library definition by its absolute path). inactive_parameters and inactive_ports: parameters and ports in inactive `ifdef branches (see below). With several definitions (copies in several trees, a library copy) and no file, the project’s copies come first, then by path. The first is always given in full. The others are taken in that order: each is given in full if the total number of parameters, ports, arguments and modports returned so far (the first definition’s included) stays at or under 200 (a separate limit from the 200-character cut on defaults), so a later, smaller definition may still be given after a large one was not. A definition that does not fit gives only its file and line and an omitted note such as pass file=tb/counter.sv to see its interface (the same as rtl/counter.sv's) (or it differs from …: its parameters, ports, arguments, modports, return type or base class do not match the first’s).
sv_find_references The uses of the declaration at a file, line and column (or of the one a use there refers to; a library file by the absolute path the tools list) across the project, as Find Usages finds them: instances, connections, calls, end labels, imports, members through handles; for a macro (at its `define or a call), its calls; when a use refers to several declarations (the same module in two libraries) all are listed and their uses merged — each use with the file, line, column, the line’s text and the unit it is in; limit (default 50) and offset page through them. inactive lists where the name is written in code an `ifdef leaves out with the defines in effect (the compile file’s and the settings’; with neither, `ifdef INC_ASSERT code is inactive), in the units of the declaration and its uses, each with the branch that leaves it out (`ifdef INC_ASSERT, `else of `ifndef SYNTHESIS; the outermost one when branches nest); for a macro also the `ifdef, `undef and `define lines naming it there. The IDE does not resolve that code, so these may be uses
sv_expand_macro What a macro call expands to, laid out for reading, as Code | Expand Macro shows it: at a file, line and column (the call whose name is there, or the innermost call whose arguments hold it), with the definitions in effect there (the file’s includes, a `define redefined before the call); or a call written as text (`uvm_component_utils(my_env)), with the project’s definitions. With the `define used: its file, line and text. An error says what stopped the expansion, after the text expanded up to it; an expansion over 20,000 characters is cut, with truncated, and a `define over 40 lines or 4,000 characters ends with …. A place in an inactive `ifdef branch is refused: that code is not compiled with the defines in effect. conditions lists the names the expansion’s `ifdefs tested and whether each was defined ({"name": "UVM", "defined": false} when the non-UVM branch was taken): define one in the compile file or the settings to get the other branch. The `define’s within lists the `ifdef branches it sits in (`else of `ifdef UVM, `ifndef DATA_W for a default the command line may override; include guards left out): with other defines another definition may apply
sv_instances The static hierarchy around a module, interface or program, not elaborated: instantiated_by, every instance of it in the project, with the unit holding it, the instance name (an array with its dimensions, u_arr[3:0]) and the file, line and column of that name, paged with limit (default 50) and offset and a total; instantiates, the instances it holds, then those bind directives add to it, with the unit named and its kind (module, interface, program, checker, primitive, macro when a macro call names the unit; none when no definition is found). An instance in a generate construct says for, if or case (the innermost); one a bind adds belongs to the target and gives the target as written (tgt: t1, t2 for some of its instances, top.u_mid for one instance by its path). A macro whose `define body instantiates the unit by name creates an instance at each of its calls: listed at the call, named as the call’s arguments make it (`PRIM_FLOP_SPARSE_FSM(u_state_regs, …) gives u_state_regs, once although the body’s `ifdef branches both write it), with via_macro naming the macro; instantiates lists them too. A macro whose body calls such a macro (`INST_PAIR(u_pair) calling `INST_LEAF twice) creates its instances too, up to 8 levels: listed at the outer call, named through every level, with body_macro naming the macro whose body writes them. The formals in the body’s instance name are replaced by the call’s arguments, in array dimensions too, or by their defaults. Such an instance’s connections are written in that macro’s body, not at the call. Macros whose bodies lead to no instance are not expanded; past 1,000 expansions from one call the rest are left out and macro_expansion_cut says so. An interface used as a port type is not an instance, and gates (and g(…)) are not listed. Only active code is seen: an instance in an inactive `ifdef branch is not listed. With several definitions of the name (copies in several trees, a library copy) and no file, the project’s copies come first, then by path. The first definition is always listed. The others are taken in that order: each is listed if the total number of instantiated_by and instantiates entries returned so far (each list as cut to limit, the first definition’s included) stays at or under 2 × limit, so a later, smaller definition may still be listed after a large one was not. A definition that does not fit gives no entries, only instantiated_by_total, instantiates_total and an omitted note such as pass file=tb/counter.sv to list its instances (it holds 3); paging with offset does not reach it.
sv_drivers What drives a signal (a variable, net or port) and, with loads (default false), what reads it, at a file, line and column of its declaration or a use: drivers and loads, each place with its kind (assign; always_ff, always_comb, always_latch, always, initial, final, task, function for a procedural assignment or a read in one, procedural elsewhere; force; initializer; instance_output, instance_input, instance_inout for an instance’s port by its direction; port_input, port_output, port_inout for the unit’s own port; gate; instance_connection for a parent’s connection; read for any other read), file, line, column, the line’s text and the unit; partial when a select or struct field is written (v[2] <=, s.f =). x++ and x += 1 are in both lists. A task’s or function’s output, inout or ref argument, h = new(), and the system tasks that write an argument ($readmemh, $cast, $sscanf, std::randomize, …) are drivers. With depth (default 1, 0 to 8) it follows the static hierarchy that many levels: an instance_output driver continues with the child’s drivers of that port, a port_input with each parent’s connection to it and what drives the signals connected there; loads likewise. Each instance of a child is followed on its own. Those places say via: the instances between the signal’s unit and the place’s, outermost first, then the port (u_counter.count; two levels down u_mid.u_in.o, two levels up u_w.u_top.in_a). A chain goes one way, not back. Drivers: down into the child from an output connection, up to the parents from an input port. Loads the other way: up to the parents from an output port, down into the child from an input connection. Not elaborated: every instance counts, parameters are not evaluated and every generate branch is seen. unknown lists uses whose effect is not known: kind instance (a connection to a module not found or defined twice), macro (for a port, a connection written in a `define body that instantiates its module), macro_call (the signal passed to a macro call, such as `MY_FLOP(q, d)); inactive the name in code an `ifdef leaves out. limit (default 50) applies to each list; drivers_total, loads_total (left out when loads is false) and unknown_total count every place, more says a list was cut. On a very large fan-out the hierarchy is followed for at most about 2,000 places (more with a larger limit); hierarchy_cut then says some places were not followed into, and the totals count what was reached. A name that is not a variable, net or port is refused: use sv_find_references
sv_expand_autos verilog-mode AUTOs expanded in the files named, as Expand AUTOs writes them. By default a dry run: per file, changed and a unified diff as diff -u writes it (--- a/<file> / +++ b/<file>, 3 lines of context, LF lines, a last line without a newline marked; cut at 50,000 characters with truncated), nothing written. With apply set, the change is made as one undoable Expand AUTOs command per file and saved, so the agent reads it on disk; the file keeps its line separators (CRLF stays CRLF). not_supported names the AUTOs left as they are; error says why a file was not expanded (a module whose definition is not found, …) or not applied, and the other files still are. A file is not applied when it has unsaved changes in an editor (saving would write them too; its dry run reads the editor text and says editor_buffer_differs), when it changed after it was read, or when it is read-only; one the IDE could not save is changed in the IDE and says so. Out of time, the files expanded so far are returned with timed_out; with apply, a changed file that was not written says so (none is written unless every file was expanded first)
sv_rename A declaration renamed with every use of it, as Rename makes it: overrides of a virtual method or a constraint, end labels and .name port connections (.clk becomes .clock(clk)) go with it, and a module’s name in the verilog-mode AUTO_TEMPLATE heads of the files with its instances (/* legacy_reg AUTO_TEMPLATE (), so the next sv_expand_autos still applies the template. The agent names the declaration by its name as written in a file: every declaration of the name written there and every declaration its uses there refer to count, and those one rename changes together (a virtual method and its overrides) count once. When they are more than one (a property and a constructor argument both called data), the error lists them with their lines and kinds; line says which line, and kind which declaration (.clk refers to a port and to a signal). A macro’s expansion, a library file and an invalid name or keyword are refused. Otherwise code only: comments and strings are not changed, the file is not renamed, and the alignment of the lines changed is not redone. By default a dry run: the target (port 'done' in rtl/counter.sv:5), a unified diff per file, the number of places, the conflicts (the messages of Rename conflicts) and notes (what it also renames: also renames function 'area' in classes/circle.sv:12 for an override, another declaration of the name, an AUTO_TEMPLATE head; and, for a port, signal or parameter of a module, where .name follows a path the IDE cannot resolve and is not renamed (code and macro bodies, not comments or strings; a .name that resolves to something else, such as a struct field, is not listed), such as __name.state_o in a macro or `TOP_HIER.u.state_o; and where the name is written in code an `ifdef leaves out, in the units the rename changes, with the branch: not renamed: 'state_o' in inactive code … at rtl/flop.sv:4 (`ifdef INC_ASSERT)), nothing written; editor_buffer_differs lists files whose unsaved editor text was read. With apply set, the whole rename is made as one undoable command and saved. It is not applied when there are conflicts (unless ignore_conflicts), when a file it changes has unsaved changes in an editor, is read-only or changed while the rename was computed; then nothing is changed. After applying, the result has the real diffs, and says so if any file changed differently from the dry run. Diffs are taken in this order: the declaration’s file; after applying, the files that changed differently from the dry run; then the other files by path. Each diff is included if the total diff text so far stays at or under 40,000 characters; otherwise that file is listed with truncated: true and no diff (the declaration’s file too, if its own diff is that large), and later, smaller diffs may still be included. notes then says how many were left out: diffs of 3 files left out (the answer's budget): they are changed too; read them on disk after applying. A file left out this way is still part of the rename: places counts it and apply changes it. A dry run cannot show its diff; to review it, apply the rename, read the file on disk or with git diff, and undo once (Edit | Undo in the IDE, ⌘Z / Ctrl+Z) to revert the whole rename if needed (apply needs ignore_conflicts when the dry run lists conflicts). The result after applying is cut the same way.
sv_apply_fix One of the quick fixes sv_check lists, as the IDE’s Alt+Enter applies it: at the problem’s file, line and column (any place inside the problem), by the fix’s exact name (fix), with rule (the problem’s rule from sv_check) to choose between problems at one place. By default a dry run: the change as a unified diff, nothing written; with apply set, one undoable command, saved, and the diff of what was written (error says so if it differs from the dry run). Refused with what is offered there when the place has no problem with that fix (the fixes listed per rule), when the fix needs the IDE’s interactive editor, or, with apply, when the file has unsaved editor changes. Syntax errors and slang’s problems have no fixes. It works on the file as written (on disk, or in an editor: a dry run of unsaved editor text says editor_buffer_differs); after a check of proposed content, write the file first. A read-only file is refused
sv_create_compile_file Makes a compile file (.f) from a top module, for a project that has none or to compare with yours. It lists the files the top needs: its instance tree (generate blocks too, and the checkers and user-defined primitives it instantiates), the interfaces its ports name, the packages its files import or name with pkg:: (in parameter defaults and port types too), the bind statements written in those files, and the files defining macros they use without including them (the macro-definition files a hand-written .f usually lists first), with the units those files declare. A macro used inside another macro’s body counts too; a macro set in Extra defines in the SystemVerilog settings or in the active compile file’s +define+ needs no file (for the latter, notes says to add it to Extra defines, because the new file has no defines). A file that undefines a macro again (`undef) does not provide it; only .sv, .svh and .v files are searched. Order: the files others need come first, each after the files whose macros or packages it uses (ties: files that only define macros, then packages, then the others); then the rest. The files are read as one compilation unit. Files that need each other first (a package using a module file’s macro while the module imports the package) cannot be ordered: notes says so. Included files are headers, not sources, whatever their extension: their folders become +incdir+ lines. Paths are relative to the .f file’s folder. When a design unit (module, interface, program, checker, primitive), package or macro is defined in several files, the one in a prefer directory wins (prefer is a list of project-relative directories), then the one the active compile file lists (a source, or under one of its library (-y) directories), then one in a directory already chosen, then the one whose folder shares the most folders with the top module’s file. The answer has text (cut at 20,000 characters), path, ambiguous (names with several definitions that no rule could choose between; the first was used), unresolved (units and `macros defined nowhere, each macro once with where it is first used and how many more files use it, and `include files found nowhere), macro_files (the files added for their macros, and headers another file includes whose macros a file uses without including them, with the macro and where it is used), binds_available (files outside the design with bind statements into it, such as testbench or formal-verification files: not taken), applied (whether the file was written) and notes. A dry run by default. apply=true writes it inside the project at path (default <top>.f in the project’s folder), not over an existing file unless overwrite=true. With use (default true) it becomes the project’s compile file; a Working directory set in Settings | Languages & Frameworks | SystemVerilog is cleared, because the paths in the new file start at its own folder, and notes says so
sv_run Runs one of the project’s SystemVerilog Studio run configurations for Verilator or Icarus Verilog (lint, build, or build and run the simulation), by its configuration name, and parses the output: problems (severity, file, line, column, message, tool_code: Verilator’s warning name, sorry, UVM_ERROR), the tool’s errors and warnings, the uvm report counts (from the UVM report summary when it is printed, else from the report lines), passed (exit code 0, no errors, no UVM_ERROR/UVM_FATAL, not timed out), exit_code, duration_ms, the last lines of the output (log_tail, up to 200 lines) and the whole output in log_file (the last 20 runs are kept). A failing step stops the run. Allowed only when you turn on Agents may run SystemVerilog tools in Settings | Languages & Frameworks | SystemVerilog | Coding Agents (off by default), in a trusted project, for verilator, iverilog and vvp installed outside the project and the simulation Verilator builds in obj_dir (more executables can be allowed there by absolute path or file name; one inside the project or the working directory only by its absolute path, which also applies to simulators installed under a project or working directory at your home folder). Turning it on lets agents run code: whatever the design and compile files make the tools run ($system, DPI code, compiler flags in a .f file), and agents can edit those files. Refused for waveform viewer and verilog-auto configurations, with SystemVerilog or compile files (.f) unsaved in an editor, and while the configuration’s working directory is in use. timeout is up to 10 minutes; the run’s processes are stopped on time-out or when the agent’s call is cancelled; output past 256 MB stops the run (output_limit_reached). exit_code is empty when the run was stopped. Builds and simulations write files (obj_dir, dumps); before-run tasks are not run (before_run_skipped). The setting applies to all projects in the IDE and is not synced to other machines. Use it instead of the IDE’s own execute_run_configuration for SystemVerilog tools
sv_outline A file as a compact outline, in place of reading it: each module, interface, program, package, class, interface class, checker and primitive, and in text order its parameters and ports (as sv_module_interface gives them), an interface’s modports, signals (type and width as written), instances (unit, generate kind), assign/always*/initial/final blocks with the signals they assigns (not a block’s own loop variables, not the arguments of macro calls; a write through a path, also as an argument such as $cast(obj.x, v), is given up to the first name it changes: a struct, such as s for s.f, else the whole path from its first name, such as bus.req or obj.x (a leading $root. or pkg:: is left out)), functions and tasks with their header (signature, also extern and pure virtual ones and out-of-class bodies such as c::f), typedefs, a class’s own properties, methods and constraints; an included header’s file-scope parameters, typedefs and functions, with no inside. Signals a macro declares, covergroups, sequences, properties, clocking blocks and assertions are not listed. Each entry has its kind, name, line (and end_line for units, blocks and subroutines) and inside (the unit). Code in an inactive `ifdef branch is not listed: inactive_ranges gives its lines and branch. limit (default 200, at most 1000) counts every entry, offset pages, total counts all; with content, the outline of proposed text without writing it. editor_buffer_differs says the file has unsaved editor changes (they were outlined). A file over the IDE’s size limit is refused.
sv_members The members of a class with its base classes (inherited, default true), or the fields of a struct or union typedef, or the literals of an enum typedef (ST[3] gives ST0…ST2): name, kind (property, function, task, constraint, covergroup, typedef, class, parameter, field, literal), type as written, bound_type when the type is a base class’s type parameter the class binds, qualifiers (rand, local, protected, static, virtual, …), a method’s arguments, declared_in for an inherited member, overrides when a member of the class replaces a base class’s, via_macro for a member a class-level macro call declares, file, line and column. extends lists the base classes as written, nearest first. A base class’s local members and its new are not listed (a subclass cannot use them). complete is false, with why, when members may be missing (a base class not found, a class-level macro the IDE cannot expand, an `include in a class body the IDE does not find, a macro among a struct’s members, an enum range of more than 1,024 literals). An interface class’s first base is followed and implements is not shown; typedefs inside a module, interface or class are not found (package and compilation-unit ones are). Paged with limit (default 100) and offset. When the name has several definitions (a design copied into several trees, a library copy) and no file is given, the project’s copies come first (then by path), and the first definition is always listed (paged with limit and offset); the others are taken in that order and each is listed if the members listed so far (the first definition’s included) stay within limit; the others are given only as a summary: each gives its total and an omitted note naming the file to pass and saying whether its members match the first definition’s. Paging with offset does not reach them (more is false)
sv_check The problems in the files named: syntax errors and the SystemVerilog inspections (instance connections, also of instances macro calls create, unknown class members and names through an instance (u_sub.no_such_sig), unconnected inputs, connection widths, missing call arguments, names from packages not imported, as enabled in your inspection profile), each with the rule, the severity, the 1-based line and column of its start and end, the message and the quick fixes by name. Per file, unresolved lists the packages, included files, macros and base classes it uses that are not found (for a file `included into a package, also the packages that package imports) (UVM not configured, a file generated at build time): the checks that need those names are skipped there, so no problems is not a pass; checked is false for a file the limit left out. With content and one file, checks that text as the file without writing it; see “Check this edit before you write it” under Check what the agent wrote. Each file has a verdict: fail (an error, the plugin’s or slang’s, also beyond the limit), incomplete (no error, but unresolved names), pass, or not_checked; warnings do not fail. When slang is installed, its compile results are added: each problem says its engine (svstudio or slang, slang’s rule as slang:<Code>), one the plugin also reports on that line is given once with confirmed_by: "slang", each file has its slang state (pass, fail, not_compiled for unsaved changes or content, not_in_design), and the answer’s slang says compiled (with the version, options not passed and design-wide problems), not_compiled or unavailable with the reason
sv_hierarchy The elaborated design, as the Design Hierarchy shows it (needs slang-server): from a hierarchical path (default "": the top instances and packages) down depth levels (1 to 8, default 1), each item with its name, path (to pass on), kind (Instance, Scope or ScopeArray for generate blocks, Package, Param, Port, Logic, …), an instance’s module, a parameter’s elaborated value, a port’s or variable’s type, its file, line and column, and has_children; with module, the instances of that module by path. Parameters are propagated and generate loops unrolled (top.g_lane[1]), unlike sv_instances. limit (default 200) counts items over all levels, more says some were left out; state is unavailable with a reason without slang-server or a compile file; problems lists what slang-server could not load. A path not in the design is refused with what to ask instead. search finds items by name anywhere in the design (fuzzy: the letters in order, any case; at most 100, with total; refine the query rather than page): each with its path, kind, an instance’s module, a signal’s or parameter’s type (and a parameter’s value), and container, what holds it as slang-server names it (the module, or a generate scope such as top.g_lane[0]). list="modules" gives every module with its instance count (and the path when it has one); each is given alone, with limit
sv_elaborated_drivers What drives a signal in the elaborated design (or, with loads, what reads it), by its hierarchical path (top.u_fifo.dout), as slang-server sees it: through ports and per instance, breadth-first up to depth levels (1 to 4, default 1). Each signal has its path, the file, line and column of its declaration, via (the signal it was reached from; at level 1 the one asked about), level, and self when a signal feeds itself (a counter). precision is block: within a procedural block every signal it assigns counts for each of them, so use sv_drivers (statement-precise, at a source position, static) to see the exact assignment. limit (default 50) counts signals over all levels, more says some were left out; not_followed lists signals reached that slang-server could not follow further, with its words. A bit select, an instance path or a path not in the design is refused with what to pass instead; unavailable with a reason without slang-server or a compile file; editor_buffer_differs lists design files with unsaved changes (slang-server read the disk)

A module may declare a parameter or a port inside an `ifdef in its #(…) parameter list or its (…) port list, so that it exists only in some builds. When that branch is inactive with the defines in effect (the compile file’s, the settings’ and `defines earlier in the file or in files it includes; see Conditional compilation), sv_module_interface does not list the name in parameters or ports; it lists it separately, in inactive_parameters or inactive_ports. The agent then knows the port exists only in other builds: it should not connect it as an ordinary port (in this build it does not exist), and if it must be connected, it connects it inside the same `ifdef. If the agent gets this wrong, tell it so.

For this module, with neither SIMULATION nor SYNTHESIS defined:

module cond #(
parameter int Width = 1
`ifdef SIMULATION
, parameter CustomForceName = ""
`endif
) (
input logic clk_i
`ifndef SYNTHESIS
, output logic trace_o
`else
, input logic scan_i, output logic [1:0] scan_o
`endif
);
endmodule

the unit’s entry in units has parameters with Width only, ports with clk_i and trace_o (the active `ifndef SYNTHESIS branch), and next to them:

part of sv_module_interface cond
"inactive_parameters": [{"name": "CustomForceName", "condition": "`ifdef SIMULATION"}],
"inactive_ports": [
{"name": "scan_i", "condition": "`else of `ifndef SYNTHESIS"},
{"name": "scan_o", "condition": "`else of `ifndef SYNTHESIS"}
]
  • Each entry has the name and the condition: the branch as written (`ifdef X, `elsif Y, `else of `ifndef X). When branches nest, the outermost inactive one: in `ifdef A (off) containing `ifdef B, the name is under `ifdef A. A localparam also has "local": true. Direction, type and width are not given.
  • A name declared in both an active and an inactive branch is in both lists: `ifdef WIDE input logic [15:0] d `else input logic [7:0] d `endif gives d in ports and in inactive_ports under `ifdef WIDE.
  • Both keys are left out when there is nothing to report. Only the two lists in a module’s header are read: an `ifdef around the whole module, or around declarations in the module body, is not reported.
You see Likely cause What to do
The agent lists no sv_ tools The MCP Server plugin is disabled, or the IDE has not been restarted since you enabled it Check Settings | Plugins, then restart the IDE
jetbrains is not connected Enable MCP Server is off, or the address in the agent differs from the one in Settings | Tools | MCP Server Turn it on and use the address shown there
The agent searches the files with grep instead It did not pick the tool Say “use the sv_ tools”, or name the tool
A port you expected under inactive_ports is in ports, or not listed at all Its branch is active: the name it tests is defined in the compile file, the settings’ extra defines or an earlier `define; or the `ifdef is outside the module’s two lists Ask the agent to run sv_project_info for the defines in effect. If the define is set on purpose, the answer is right for your build; to see the other branch, remove it from the compile file or from Extra defines in Settings | Languages & Frameworks | SystemVerilog (defines)
Empty or wrong answers A check is switched off in the inspection profile, the project is still indexing, or the agent is working in another folder than the project open in the IDE Wait for the progress bar at the bottom right; start the agent in the project the IDE has open