Problem Statement
Modern FPGA development workflows frequently require rapid module instantiation. Popular editor extensions like verilog-utils simplify this task but often strip inline commants during the transformation process. The loss of documentation fragments degrades code readability and increases maintenance overhead. To resolve this, a lightweight, clipboard-driven pipeline can be implemented using Windows Batch and Tcl/Tk, ensuring annotations remain intact while generating standardized instantiation templates.
Architecture Overview
The solution operates as a two-stage pipeline. A minimal batch launcher resolves the execution environment and invokes a Tcl/Tk script. The Tcl processor intercepts the clipboard content, parses Verilog module declarations, maps ports and parameters to instantiation syntax, preserves existing comments, and returns the formatted result to the clipboard for immediate pasting.
Launcher Batch File
Create a file named run_inst_expander.bat in a dedicated script directory. This file handles path resolution and delegates execution to the Tcl engine.
@echo off
rem Resolve absolute path of the script directory
set "SCRIPT_DIR=%~dp0"
set "TCL_PROCESSOR=%SCRIPT_DIR%expand_instance.tcl"
rem Define the Tcl/Tk wish executable location
set "WISH_EXE=C:\Program Files\Tcl\bin\wish.exe"
rem Execute the Tcl processor
"%WISH_EXE%" "%TCL_PROCESSOR%"
Core Tcl Processor
The script expand_instance.tcl replaces heavy regex substitution chains with a deterministic line-by-line parser. This structural change improves maintainability and ensures comments are handled gracefully.
# Retrieve design snippet from the system clipboard
set raw_snippet [clipboard get]
if {$raw_snippet eq ""} {
puts "Clipboard is empty. Please copy a module definition first."
exit 1
}
# Identify the module identifier
set target_mod ""
if {[regexp {module\s+(\w+)\s*#?\s*\()} $raw_snippet _ target_mod] == 0} {
if {[regexp {module\s+(\w+)\s*\()} $raw_snippet _ target_mod] == 0} {
puts "Failed to locate module declaration syntax."
exit 1
}
}
# Initialize instantiation buffer
set inst_buffer " u_${target_mod} (\n"
# Parse declaration lines
set snippet_lines [split $raw_snippet "\n"]
set is_first 1
foreach line $snippet_lines {
# Skip module headers, footers, and blank lines
if {[regexp {^\s*(module|endmodule)\s} $line] || [string trim $line] eq ""} continue
# Map parameter assignments
if {[regexp {parameter\s+(\w+)\s*=} $line _ param_id]} {
if {$is_first} {set is_first 0} else {append inst_buffer "\n"}
append inst_buffer " .${param_id}(${param_id}),"
continue
}
# Map port directions (handles optional bit widths)
if {[regexp {(input|output|inout)\s+\[?[^\]]*\]?\s+(\w+)} $line _ _ port_id]} {
if {$is_first} {set is_first 0} else {append inst_buffer "\n"}
append inst_buffer " .${port_id}(${port_id}),"
continue
}
# Retain existing comments verbatim
if {[regexp {^\s*//|^\s*/\*} $line]} {
append inst_buffer "\n${line}"
}
}
# Remove trailing comma and close instantiation
regsub {\,$} $inst_buffer "" inst_buffer
append inst_buffer "\n );"
# Update clipboard with generated template
clipboard clear
clipboard append $inst_buffer
# Allow Tk event loop to flush before exiting
after 150 { exit 0 }
VS Code Integration
Bind the external script to a keyboard shortcut using VS Code's built-in task runner. This eliminates manual terminal navigation and keeps the workflow inside the editor.
Keybindings Configuration
Add the following entry to keybindings.json. Select a chord or modifier combination that does not conflict with existing extensions.
{
"key": "alt+shift+i",
"command": "workbench.action.tasks.runTask",
"args": "verilog_instantiator"
}
Task Definition
Configure tasks.json to point to the batch launcher. Adjust the command path to match your local directory structure.
"tasks": [
{
"label": "verilog_instantiator",
"type": "shell",
"command": "D:/dev_tools/scripts/run_inst_expander.bat",
"args": [],
"presentation": {
"echo": false,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": false,
"clear": false
},
"problemMatcher": []
}
]
Operational Workflow
- Select and copy a Verilog module definition (including ports, parameters, and inline comments) using
Ctrl+C. - Trigger the bound shortcut (e.g.,
Alt+Shift+I) to invoke the Tcl procesor. - Paste the formatted instantiation block into the target design file using
Ctrl+V.
Technical Considerations
- The parser intentionally skips lines matching standard Verilog declarations, allowing custom annotations to pass through unchanged.
- Bit-width specifications (e.g.,
[7:0]) are stripped during port mapping to maintain clean instantiation syntax, as Verilog instance ports only require signal names. - If a port is entirely commented out in the source snippet, the regex will still capture it. For strict active-only mapping, additional comment-state tracking would be required in the Tcl logic.
- Ensure the Tcl/Tk distribution matches your system architecture (x86 vs x64) to prevent execution failures when invoking
wish.exe.