Tools & Productivity

GVim for VLSI Engineers

Master the editor used in every EDA terminal — from modal editing basics to Verilog macros, ctags module navigation, and the perfect .vimrc for HDL work.

Contents
  1. Why GVim for VLSI?
  2. Modal Editing — The Core Concept
  3. Essential Navigation
  4. Editing Commands
  5. Search & Replace
  6. VLSI-Specific Tricks
  7. Macros & Power Commands
  8. Split Windows & Buffers
  9. ctags — Navigate Module Hierarchy
  10. The VLSI Engineer's .vimrc
  11. Q&A

1 Why GVim for VLSI?

EDA tools — Synopsys Design Compiler, Cadence Genus, Mentor Questasim, Vivado — all run in Unix/Linux environments where Vim is the dominant editor. Many EDA GUIs embed a Vim-compatible editor. Being fluent in Vim means the same muscle memory works everywhere: on a remote server via SSH, inside the Synopsys shell, or editing a 50,000-line synthesized netlist.

2 Modal Editing — The Core Concept

Vim has distinct modes. Every key does something different depending on which mode you are in. This is what beginners find confusing and experts find powerful.

NORMAL

Navigate, delete, copy, paste, run commands. This is the default state.

Enter: Esc from any mode
INSERT

Type text as you would in any editor.

Enter: i a o I A O
VISUAL

Select text by character, line, or block for bulk operations.

Enter: v V Ctrl+v
COMMAND

Run Ex commands: save, quit, search/replace, run shell commands.

Enter: : from Normal mode
Golden rule: Press Esc whenever you're lost. It always takes you back to Normal mode. Then you can start fresh.

3 Essential Navigation

All navigation happens in Normal mode. Never use arrow keys — the hjkl keys keep your hands on the home row.

Basic Movement

KeyAction
h j k lLeft / Down / Up / Right (one character/line)
w / bNext / previous word start — jumps by identifier boundaries. In Verilog: skips over always_ff word by word
W / BNext / previous WORD — jumps by whitespace only. Faster for long signal names
e / geEnd of next / previous word
0 / ^Start of line / first non-blank character
$End of line
gg / GFirst line / last line of file
42G or :42Go to line 42 — essential for jumping to a synthesis error line number
{ / }Previous / next empty line — jumps between always blocks in Verilog
% Jump to matching bracket/parenthesis — great for checking module port lists

Screen Navigation

KeyAction
Ctrl+f / Ctrl+bPage forward / backward
Ctrl+d / Ctrl+uHalf-page down / up — smoother scrolling through long modules
zz / zt / zbCenter / top / bottom the current line on screen — use after jumping to an error
H / M / LJump cursor to top / middle / bottom of visible screen
Ctrl+o / Ctrl+iJump back / forward in jump history — returns after a gd definition jump

Search Navigation

KeyAction
/patternSearch forward for pattern
?patternSearch backward
n / NNext / previous match
*Search for the word under the cursor forward — fastest way to find all uses of a signal
#Same, backward
gdGo to local declaration of the identifier under the cursor

4 Editing Commands

Entering Insert Mode

KeyAction
i / aInsert before / after cursor
I / AInsert at start / end of line — A is the fastest way to append a semicolon
o / OOpen new line below / above and enter Insert mode
sDelete character and enter Insert mode (substitute)
cw / ciwChange word / change inner word — replaces the word under cursor
CChange from cursor to end of line
ccChange entire line

Delete, Copy, Paste

KeyAction
x / XDelete character under / before cursor
dw / diwDelete word / inner word
ddDelete (cut) entire line
DDelete from cursor to end of line
5ddDelete 5 lines — prefix any command with a count
yyYank (copy) line
yw / yiwYank word / inner word
p / PPaste after / before cursor position
u / Ctrl+rUndo / Redo
.Repeat last change — the most powerful single key in Vim. Add a port connection, then . down the list

Visual Mode Selection

KeyAction
v then motionCharacter-wise selection
VLine-wise selection — select whole lines
Ctrl+vBlock (column) selection — select a rectangle. Essential for aligning port widths
Ctrl+v then IInsert text at the start of every selected line simultaneously — add // to comment a block
gvRe-select last visual selection
Column edit trick for RTL: To add .clk(clk), style to every input port simultaneously — Ctrl+v to select the column, I to insert at beginning of each line, type your text, then Esc. All lines update at once.

5 Search & Replace

Vim's substitute command is one of its most powerful features for RTL work — renaming signals, fixing port connections, and reformatting code across an entire file.

Basic Substitute

" Replace first occurrence on current line
:s/old_sig/new_sig/

" Replace ALL occurrences on current line
:s/old_sig/new_sig/g

" Replace in entire file (% = all lines)
:%s/old_sig/new_sig/g

" Replace with confirmation prompt (c flag)
:%s/old_sig/new_sig/gc

" Replace only in selected lines (Visual mode → :)
:'<,'>s/old_sig/new_sig/g

Regex Patterns Useful in Verilog

" Rename a specific wire (exact word boundary match)
:%s/\bdata_in\b/payload_in/g

" Delete all single-line comments
:%s/\/\/.*$//g

" Add .rst_n(rst_n), after every .clk(clk), line
:%s/\.clk(clk),/\.clk(clk),\r    .rst_n(rst_n),/g

" Convert 'reg' declarations to 'logic' (SV migration)
:%s/\breg\b/logic/g

" Remove trailing whitespace (keep your diffs clean)
:%s/\s\+$//e

" Add wire width — insert [7:0] before every signal named data*
:%s/wire data/wire [7:0] data/g
Case-insensitive search: Add \c anywhere in the pattern — :%s/\cAlways/always/g matches regardless of case. Useful when cleaning up auto-generated netlists with inconsistent casing.

Global Command — :g

The :g command runs a command on every line that matches a pattern. More powerful than substitute for structural operations.

" Delete all lines containing 'timescale'
:g/timescale/d

" Print all lines containing 'always_ff' (like grep)
:g/always_ff/p

" Move all 'input' port lines to end of file
:g/^\s*input/m$

" Delete all blank lines
:g/^$/d

" Add a comment above every 'module' declaration
:g/^module/normal O// Module definition

6 VLSI-Specific Tricks

Syntax Highlighting for Verilog / SystemVerilog

Modern Vim (8.x+) and GVim include built-in Verilog syntax highlighting. For SystemVerilog, you need a plugin or an updated syntax file.

" In .vimrc — enable filetype detection and syntax
filetype plugin indent on
syntax on

" Associate .sv and .svh files with SystemVerilog
autocmd BufRead,BufNewFile *.sv,*.svh  set filetype=systemverilog
autocmd BufRead,BufNewFile *.v,*.vh   set filetype=verilog

Folding — Collapse always Blocks

Folding lets you collapse sections of a large RTL file to see just the module skeleton.

" Enable syntax-based folding
set foldmethod=syntax
set foldlevel=1     " open 1 level deep by default

" Fold commands (Normal mode)
zo   " open fold under cursor
zc   " close fold under cursor
zR   " open ALL folds in file
zM   " close ALL folds in file
za   " toggle fold under cursor

Aligning Port Connections

When writing module instantiations, aligning the .port(signal) column makes code readable. Use the :! shell escape to pipe through a formatter, or use visual block mode:

" Use column alignment via external tool (if installed)
:'<,'>!column -t

" Manually align with Visual Block — select width column
" Ctrl+v → select column → r (replace with spaces)

Navigating Synthesis Error Line Numbers

When DC or Genus reports Error at line 847, jump directly from the terminal:

# From shell — open file at a specific line
gvim +847 top.v
vim +847 top.v

" From inside Vim — jump to line
:847
" or in Normal mode
847G

Comparing Two Files (vimdiff)

Compare two versions of an RTL file side by side — essential for reviewing synthesis-modified netlists or tracking down what changed between runs.

# From shell
vimdiff rtl_v1.sv rtl_v2.sv
gvimdiff rtl_v1.sv rtl_v2.sv

" Navigate differences
]c   " jump to next difference
[c   " jump to previous difference
do   " diff obtain — pull change from other window
dp   " diff put — push change to other window

Reading Shell Output Into the Buffer

" Insert output of a shell command at cursor
:r !grep "always_ff" ../rtl/top.sv

" Replace current line with command output
:.!date

" Run synthesis and read errors into a scratch buffer
:r !dc_shell -f run.tcl 2>&1 | grep Error

7 Macros & Power Commands

A Vim macro records a sequence of keystrokes and replays them. For repetitive RTL tasks — formatting 30 port connections identically, adding a suffix to 20 signal names — a macro beats writing a script.

Recording and Playing a Macro

" Record macro into register 'a'
qa           " start recording into register a
...          " perform your keystrokes
q            " stop recording

@a           " play macro 'a' once
10@a         " play macro 'a' 10 times
@@           " repeat last macro

Practical RTL Macro: Format a Port Connection

Task: convert bare signal names to .sig_name(sig_name), format across 20 lines.

" Assume cursor is on a line containing: "  data_in"
" Macro recorded in register 'p':

qp           " start recording
^            " go to first non-blank char
i.           " insert '.' before signal name
<Esc>
e            " jump to end of signal name
a(           " append '('
<Esc>
yiw          " yank the word (signal name)
ea           " go to end, enter insert
),           " close port connection
<Esc>
j            " move to next line
q            " stop recording

19@p         " repeat for remaining 19 lines

Abbreviations — Instant Code Templates

" In .vimrc — type 'aff' in insert mode → expands to always_ff template
iabbrev aff always_ff @(posedge clk or negedge rst_n) begin<CR>end

iabbrev acb always_comb begin<CR>end

iabbrev mod module  ();<CR><CR>endmodule

Marks — Bookmark Locations in a File

" Set mark 'a' at current line
ma

" Jump back to mark 'a'
`a   " exact position
'a   " beginning of the marked line

" Use case: mark the top of an always block (ma),
" scroll to find the signal, fix it, then 'a to return

8 Split Windows & Buffers

Open your DUT and testbench side by side, or keep a synthesis report open while editing RTL.

Splitting Windows

CommandAction
:sp file.svHorizontal split — open file.sv above current
:vsp file.svVertical split — open file.sv to the right
Ctrl+w h/j/k/lMove focus between split windows
Ctrl+w =Equalize all window sizes
Ctrl+w > / <Increase / decrease vertical split width
Ctrl+w _Maximize current horizontal window
:qClose current split
:onlyClose all splits except current

Buffers — Managing Multiple Files

" Open multiple files into buffers
vim *.sv

:ls          " list all open buffers
:b2          " switch to buffer 2
:bn / :bp    " next / previous buffer
:b top.sv    " switch to buffer by filename
:bd          " delete (close) current buffer

Tabs

:tabnew file.sv    " open file in a new tab
gt / gT            " next / previous tab
:tabclose          " close current tab
Workflow tip: Open your DUT in one vertical split and the testbench in the other with :vsp tb_top.sv. Use Ctrl+wl and Ctrl+wh to switch. Set scrollbind if you want them to scroll together during review.

9 ctags — Navigate Module Hierarchy

ctags builds an index of all module, function, and task definitions in your RTL. From any file, you can jump instantly to where a module is defined — without grep.

Setup

# Install ctags (Universal Ctags recommended)
sudo apt install universal-ctags   # Ubuntu/Debian
brew install universal-ctags       # macOS

# Generate tags for all Verilog/SV files in project
ctags -R --languages=Verilog,SystemVerilog *.v *.sv src/

# Or — generate tags for a whole project recursively
ctags -R --exclude=sim --exclude=work .

Using Tags in Vim

CommandAction
Ctrl+]Jump to definition of the word under cursor — e.g., jump from module instantiation to module definition
Ctrl+tJump back to where you came from (tag stack)
:tag module_nameJump to definition of a specific module by name
:ts module_nameShow all matching tags (if multiple modules share a name)
:tn / :tpNext / previous match in tag list
Ctrl+w Ctrl+]Open tag definition in a new split window
Auto-regenerate tags: Add this to .vimrc to regenerate the tag file every time you save a .sv file: autocmd BufWritePost *.sv,*.v silent! !ctags -R &. The & runs it in the background so Vim doesn't freeze.

10 The VLSI Engineer's .vimrc

Drop this into ~/.vimrc (Linux/macOS) or $HOME/_vimrc (Windows). It configures Vim for productive RTL and HDL work.

~/.vimrc — VLSI Engineer Edition
" ─── Core Settings ─────────────────────────────────────────
set nocompatible          " use Vim improvements, not vi compatibility
syntax on                 " syntax highlighting
filetype plugin indent on " filetype-aware indenting

" ─── Display ────────────────────────────────────────────────
set number                " show line numbers
set relativenumber        " relative line numbers (faster navigation)
set cursorline            " highlight current line
set colorcolumn=100      " show column guide at 100 chars
set scrolloff=6          " keep 6 lines visible above/below cursor
set laststatus=2         " always show status bar
set ruler                 " show line/column in status bar
set showcmd               " show partial commands in bottom right
set wildmenu              " enhanced command completion

" ─── Indentation (RTL standard: 2-space indent) ─────────────
set expandtab             " spaces, not tabs
set tabstop=2
set shiftwidth=2
set softtabstop=2
set autoindent
set smartindent

" ─── Search ─────────────────────────────────────────────────
set hlsearch              " highlight search results
set incsearch             " search as you type
set ignorecase            " case-insensitive search
set smartcase             " ...unless pattern has uppercase

" ─── File Handling ──────────────────────────────────────────
set hidden                " allow switching buffers without saving
set autoread              " auto-reload files changed outside Vim
set noswapfile            " no swap files (cleaner EDA directories)
set nobackup
set undofile              " persistent undo across sessions
set undodir=~/.vim/undo// " store undo files here (create dir first)

" ─── Clipboard ──────────────────────────────────────────────
set clipboard=unnamed      " yank goes to system clipboard (GVim/macOS)

" ─── Filetypes ──────────────────────────────────────────────
autocmd BufRead,BufNewFile *.sv,*.svh  set filetype=systemverilog
autocmd BufRead,BufNewFile *.v,*.vh   set filetype=verilog
autocmd BufRead,BufNewFile *.tcl      set filetype=tcl

" ─── Folding ────────────────────────────────────────────────
set foldmethod=syntax
set foldlevelstart=2
nnoremap <space> za       " toggle fold with spacebar

" ─── Key Mappings ───────────────────────────────────────────
let mapleader = ","

" Clear search highlight
nnoremap <leader>/ :nohlsearch<CR>

" Save with ,w
nnoremap <leader>w :w<CR>

" Toggle line numbers
nnoremap <leader>n :set relativenumber!<CR>

" Open tag in vertical split
nnoremap <leader>] :vsp <CR>:exec("tag ".expand("<cword>"))<CR>

" Quick buffer navigation
nnoremap <leader>b :ls<CR>:b<space>

" Strip trailing whitespace on save
autocmd BufWritePre *.v,*.sv,*.svh :%s/\s\+$//e

" Auto-regenerate ctags on save
autocmd BufWritePost *.v,*.sv silent! !ctags -R &

" ─── RTL Abbreviations ──────────────────────────────────────
iabbrev aff  always_ff @(posedge clk or negedge rst_n) begin
iabbrev acb  always_comb begin
iabbrev alb  always_latch begin
iabbrev gen  generate
iabbrev endg endgenerate

" ─── GVim-specific ──────────────────────────────────────────
if has('gui_running')
  set guifont=JetBrains\ Mono:h13
  set lines=45 columns=160
  set guioptions-=T          " hide toolbar
  set guioptions-=m          " hide menu bar
  colorscheme desert
endif
Create the undo directory first: Run mkdir -p ~/.vim/undo before using this config, or Vim will show an error on startup.

11 Q&A

I accidentally typed in Normal mode and the file looks corrupted. How do I undo?

Press Esc first to make sure you're in Normal mode, then press u repeatedly to undo. Vim has unlimited undo by default. If you want to undo all changes and return to the saved version, use :e! — this reloads the file from disk, discarding all unsaved changes. With undofile set in your .vimrc, you can even undo changes from previous sessions.

How do I search for a signal name that contains special characters like [ ] or ( )?

Escape the special characters with a backslash: /data\[7:0\] to search for data[7:0]. Alternatively, use \V (very no-magic mode) which treats everything literally except \: /\Vdata[7:0] searches for the exact string with no regex interpretation. For the * under-cursor search, Vim automatically escapes the word boundary — but it won't work for non-word characters, so use / with escaping for those.

How do I open a file at a specific module inside a large RTL file?

Two approaches: (1) Open and search — vim file.sv then /module fifo_ctrl. (2) With ctags set up, use :tag fifo_ctrl from inside Vim or vim -t fifo_ctrl from the shell — Vim opens the correct file at the exact line of the module definition. This is the fastest way once your tags file is generated.

How do I comment out a block of 20 lines at once?

Use Visual Block mode: position cursor at the first line, press Ctrl+v, then 20j to select 20 lines down. Press I (capital i) to insert at the beginning of all selected lines, type //, then press Esc. All 20 lines get // prepended simultaneously. To uncomment, select the same block with Ctrl+v, use 2l to extend the block 2 characters wide (covering //), then press d to delete.

What's the fastest way to duplicate a module port list and turn it into an instantiation?

Select the port declaration block with V and motion keys, then y to yank, move to destination, p to paste. Then use a macro or :%s to transform input logic [7:0] data_in.data_in(data_in). The substitute: :'<,'>s/\s*\(input\|output\|inout\)\s\+\(logic\|wire\|reg\)\s\+\(\[.*\]\s\+\)\?\(\w\+\)/ .\4(\4)/g strips the direction/type and wraps in dot-port notation. Keep this regex in your notes — it's one of the most useful RTL substitutions.

How do I run a Tcl or compilation script from inside GVim and see the output?

Use :! to run a shell command: :!dc_shell -f synth.tcl 2>&1 | tee synth.log. The output appears in a terminal pane and you press Enter to return to Vim. To read the output directly into a new buffer for easier navigation: :new | r !vlog -sv top.sv 2>&1. This opens a split with the compiler output, letting you use Vim's search to find errors. Map this to a leader key for a one-key compile-and-check workflow.

My .vimrc settings aren't being applied to .sv files. Why?

Vim may not recognize .sv as SystemVerilog by default, especially on older installations. Add this to your .vimrc: autocmd BufRead,BufNewFile *.sv,*.svh set filetype=systemverilog. Also ensure filetype plugin indent on appears before any filetype-specific settings. Run :filetype inside Vim to check what filetype is detected for the current file. If it shows Off, your filetype plugin indent on line is missing or commented out.

How do I use Vim to quickly find all module instantiations of a given module across a project?

Use :vimgrep (Vim's built-in grep) to search across files and populate the quickfix list: :vimgrep /\bfifo_ctrl\b/ **/*.sv. Then navigate results with :cn (next), :cp (previous), and :copen to see the full list in a split. Alternatively, use :grep which calls the system grep for speed on large codebases: :grep -rn "fifo_ctrl" src/. Map <leader>g to :grep -rn <cword> src/<CR>:copen<CR> for a one-key project-wide signal search.